or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced.mdannotations.mdcore-injection.mdindex.mdmodules.mdmultibindings.mdproviders-scopes.mdspi.mdtypes-keys.md

annotations.mddocs/

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

```