0
# Essential Annotations
1
2
Key annotations for marking injection points, scoping instances, and creating binding qualifiers.
3
4
## Capabilities
5
6
### @Inject Annotation
7
8
Marks members (constructors, methods, fields) for dependency injection.
9
10
```java { .api }
11
/**
12
* Annotates members of your implementation class (constructors, methods,
13
* and fields) into which the Injector should inject values.
14
*/
15
@Target({METHOD, CONSTRUCTOR, FIELD})
16
@Retention(RUNTIME)
17
public @interface Inject {
18
/**
19
* If true, and the appropriate binding is not found,
20
* the Injector will skip injection of this method or field
21
* rather than produce an error.
22
* @return true if injection is optional
23
*/
24
boolean optional() default false;
25
}
26
```
27
28
**Usage Examples:**
29
30
```java
31
public class UserService {
32
// Field injection
33
@Inject
34
private DatabaseService databaseService;
35
36
// Optional field injection
37
@Inject(optional = true)
38
private CacheService cacheService;
39
40
// Constructor injection (recommended)
41
@Inject
42
public UserService(DatabaseService databaseService, LoggingService logger) {
43
this.databaseService = databaseService;
44
this.logger = logger;
45
}
46
47
// Method injection
48
@Inject
49
public void setConfiguration(Configuration config) {
50
this.config = config;
51
}
52
53
// Optional method injection
54
@Inject(optional = true)
55
public void setMetrics(MetricsService metrics) {
56
this.metrics = metrics; // Only called if binding exists
57
}
58
}
59
```
60
61
### @Singleton Annotation
62
63
Scope annotation ensuring only one instance per Injector.
64
65
```java { .api }
66
/**
67
* Apply this to implementation classes when you want only one instance
68
* (per Injector) to be reused for all injections.
69
*/
70
@Target({TYPE, METHOD})
71
@Retention(RUNTIME)
72
@ScopeAnnotation
73
public @interface Singleton {}
74
```
75
76
**Usage Examples:**
77
78
```java
79
// Singleton class
80
@Singleton
81
public class DatabaseConnectionPool {
82
private final List<Connection> connections;
83
84
@Inject
85
public DatabaseConnectionPool(DatabaseConfig config) {
86
this.connections = createConnections(config);
87
}
88
}
89
90
// Singleton binding in module
91
public class DatabaseModule extends AbstractModule {
92
@Override
93
protected void configure() {
94
bind(DatabaseService.class).to(PostgreSQLService.class).in(Singleton.class);
95
}
96
}
97
98
// Singleton provider method
99
public class ConfigModule extends AbstractModule {
100
@Provides
101
@Singleton
102
Configuration provideConfiguration() {
103
return Configuration.load("app.properties");
104
}
105
}
106
```
107
108
### @Provides Annotation
109
110
Marks methods in Modules as provider methods for creating bindings.
111
112
```java { .api }
113
/**
114
* Annotates methods in Modules to create bindings. The method's return type
115
* is bound to its returned value. Guice will pass dependencies to the method
116
* as parameters.
117
*/
118
@Target(METHOD)
119
@Retention(RUNTIME)
120
public @interface Provides {}
121
```
122
123
**Usage Examples:**
124
125
```java
126
public class ApplicationModule extends AbstractModule {
127
@Override
128
protected void configure() {
129
// Regular bindings here
130
}
131
132
// Simple provider method
133
@Provides
134
DatabaseConfig provideDatabaseConfig() {
135
return new DatabaseConfig("localhost", 5432, "myapp");
136
}
137
138
// Provider method with dependencies
139
@Provides
140
DatabaseService provideDatabaseService(DatabaseConfig config, Logger logger) {
141
return new PostgreSQLService(config, logger);
142
}
143
144
// Singleton provider method
145
@Provides
146
@Singleton
147
ConnectionPool provideConnectionPool(DatabaseConfig config) {
148
return new HikariConnectionPool(config);
149
}
150
151
// Named provider method
152
@Provides
153
@Named("primary")
154
Cache providePrimaryCache() {
155
return new RedisCache("primary-redis:6379");
156
}
157
158
// Provider method with complex initialization
159
@Provides
160
EmailService provideEmailService(
161
@Named("smtp.host") String smtpHost,
162
@Named("smtp.port") int smtpPort,
163
EmailConfig config
164
) {
165
EmailService service = new EmailService();
166
service.configure(smtpHost, smtpPort);
167
service.setTemplateDirectory(config.getTemplateDir());
168
service.initialize();
169
return service;
170
}
171
}
172
```
173
174
### @Named Annotation
175
176
Binding annotation for distinguishing multiple bindings of the same type by name.
177
178
```java { .api }
179
/**
180
* Annotates named things.
181
*/
182
@Retention(RUNTIME)
183
@Target({FIELD, PARAMETER, METHOD})
184
@BindingAnnotation
185
public @interface Named {
186
String value();
187
}
188
```
189
190
**Usage Examples:**
191
192
```java
193
// Multiple bindings of the same type
194
public class CacheModule extends AbstractModule {
195
@Override
196
protected void configure() {
197
bind(Cache.class).annotatedWith(Names.named("primary"))
198
.to(RedisCache.class);
199
bind(Cache.class).annotatedWith(Names.named("secondary"))
200
.to(MemcachedCache.class);
201
bind(Cache.class).annotatedWith(Names.named("local"))
202
.to(InMemoryCache.class);
203
}
204
}
205
206
// Provider methods with names
207
public class DatabaseModule extends AbstractModule {
208
@Provides
209
@Named("primary-db")
210
DatabaseConnection providePrimaryConnection() {
211
return DriverManager.getConnection("jdbc:postgresql://primary-db/app");
212
}
213
214
@Provides
215
@Named("secondary-db")
216
DatabaseConnection provideSecondaryConnection() {
217
return DriverManager.getConnection("jdbc:postgresql://secondary-db/app");
218
}
219
}
220
221
// Injection with named dependencies
222
public class UserRepository {
223
private final DatabaseConnection primaryDb;
224
private final DatabaseConnection secondaryDb;
225
private final Cache primaryCache;
226
227
@Inject
228
public UserRepository(
229
@Named("primary-db") DatabaseConnection primaryDb,
230
@Named("secondary-db") DatabaseConnection secondaryDb,
231
@Named("primary") Cache primaryCache
232
) {
233
this.primaryDb = primaryDb;
234
this.secondaryDb = secondaryDb;
235
this.primaryCache = primaryCache;
236
}
237
}
238
239
// Constants binding with names
240
public class ConfigModule extends AbstractModule {
241
@Override
242
protected void configure() {
243
bindConstant().annotatedWith(Names.named("api.timeout")).to(30000);
244
bindConstant().annotatedWith(Names.named("api.retries")).to(3);
245
bindConstant().annotatedWith(Names.named("app.version")).to("1.2.0");
246
}
247
}
248
```
249
250
### @BindingAnnotation Meta-Annotation
251
252
Meta-annotation for creating custom binding annotations.
253
254
```java { .api }
255
/**
256
* Annotates annotations which are used for binding. Only one such annotation
257
* may apply to a single injection point. You must also annotate the annotation
258
* with @Retention(RUNTIME).
259
*/
260
@Target(ANNOTATION_TYPE)
261
@Retention(RUNTIME)
262
public @interface BindingAnnotation {}
263
```
264
265
**Usage Examples:**
266
267
```java
268
// Create custom binding annotations
269
@BindingAnnotation
270
@Target({FIELD, PARAMETER, METHOD})
271
@Retention(RUNTIME)
272
public @interface Primary {}
273
274
@BindingAnnotation
275
@Target({FIELD, PARAMETER, METHOD})
276
@Retention(RUNTIME)
277
public @interface Secondary {}
278
279
@BindingAnnotation
280
@Target({FIELD, PARAMETER, METHOD})
281
@Retention(RUNTIME)
282
public @interface LoggerFor {
283
Class<?> value();
284
}
285
286
// Use custom binding annotations
287
public class ServiceModule extends AbstractModule {
288
@Override
289
protected void configure() {
290
bind(DatabaseService.class).annotatedWith(Primary.class)
291
.to(PrimaryDatabaseService.class);
292
bind(DatabaseService.class).annotatedWith(Secondary.class)
293
.to(SecondaryDatabaseService.class);
294
}
295
}
296
297
// Inject with custom annotations
298
public class DataProcessor {
299
@Inject @Primary DatabaseService primaryDb;
300
@Inject @Secondary DatabaseService secondaryDb;
301
@Inject @LoggerFor(DataProcessor.class) Logger logger;
302
}
303
```
304
305
### @ScopeAnnotation Meta-Annotation
306
307
Meta-annotation for creating custom scope annotations.
308
309
```java { .api }
310
/**
311
* Annotates annotations which are used for scoping. Only one such annotation
312
* may apply to a single implementation class. You must also annotate the
313
* annotation with @Retention(RUNTIME).
314
*/
315
@Target(ANNOTATION_TYPE)
316
@Retention(RUNTIME)
317
public @interface ScopeAnnotation {}
318
```
319
320
**Usage Examples:**
321
322
```java
323
// Create custom scope annotation
324
@ScopeAnnotation
325
@Target({TYPE, METHOD})
326
@Retention(RUNTIME)
327
public @interface RequestScoped {}
328
329
// Implement the scope
330
public class RequestScope implements Scope {
331
private final ThreadLocal<Map<Key<?>, Object>> requestScopedObjects =
332
new ThreadLocal<Map<Key<?>, Object>>();
333
334
@Override
335
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
336
return () -> {
337
Map<Key<?>, Object> scopedObjects = requestScopedObjects.get();
338
if (scopedObjects == null) {
339
scopedObjects = new HashMap<>();
340
requestScopedObjects.set(scopedObjects);
341
}
342
343
@SuppressWarnings("unchecked")
344
T current = (T) scopedObjects.get(key);
345
if (current == null) {
346
current = unscoped.get();
347
scopedObjects.put(key, current);
348
}
349
return current;
350
};
351
}
352
}
353
354
// Bind the scope
355
public class WebModule extends AbstractModule {
356
@Override
357
protected void configure() {
358
bindScope(RequestScoped.class, new RequestScope());
359
360
bind(UserSession.class).in(RequestScoped.class);
361
}
362
}
363
364
// Use the custom scope
365
@RequestScoped
366
public class UserSession {
367
private String userId;
368
private Map<String, Object> attributes = new HashMap<>();
369
370
// Implementation
371
}
372
```
373
374
## Annotation Utilities
375
376
### Names Class
377
378
Utilities for working with @Named annotations.
379
380
```java { .api }
381
/**
382
* Utility methods for use with @Named.
383
*/
384
public final class Names {
385
/**
386
* Creates a @Named annotation with the given name.
387
* @param name Name for the annotation
388
* @return Named annotation instance
389
*/
390
public static Named named(String name);
391
392
/**
393
* Binds properties from a Map to named constants.
394
* @param binder Binder to use
395
* @param properties Map of property names to values
396
*/
397
public static void bindProperties(Binder binder, Map<String, String> properties);
398
399
/**
400
* Binds properties from Properties to named constants.
401
* @param binder Binder to use
402
* @param properties Properties object
403
*/
404
public static void bindProperties(Binder binder, Properties properties);
405
}
406
```
407
408
**Usage Examples:**
409
410
```java
411
// Create named annotations programmatically
412
Named primaryNamed = Names.named("primary");
413
Key<Cache> primaryCacheKey = Key.get(Cache.class, primaryNamed);
414
415
// Bind properties from configuration files
416
public class ConfigModule extends AbstractModule {
417
@Override
418
protected void configure() {
419
Properties props = new Properties();
420
props.load(getClass().getResourceAsStream("/app.properties"));
421
Names.bindProperties(binder(), props);
422
423
// Now you can inject properties like:
424
// @Inject @Named("database.url") String dbUrl;
425
// @Inject @Named("connection.pool.size") int poolSize;
426
}
427
}
428
```