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

providers-scopes.mddocs/

0

# Providers & Scopes

1

2

Custom instance creation and lifecycle management including built-in scopes and provider interfaces for complex object construction.

3

4

## Capabilities

5

6

### Provider Interface

7

8

Provides instances of type T, used for custom object creation and lazy initialization.

9

10

```java { .api }

11

/**

12

* An object capable of providing instances of type T. Providers are used in numerous

13

* ways by Guice when the default means for obtaining instances is insufficient.

14

* @param <T> the type of object this provides

15

*/

16

public interface Provider<T> extends jakarta.inject.Provider<T> {

17

/**

18

* Provides an instance of T.

19

* @return instance of T

20

* @throws OutOfScopeException when an attempt is made to access a scoped object

21

* while the scope in question is not currently active

22

* @throws ProvisionException if an instance cannot be provided. Such exceptions include messages

23

* and throwables to describe why provision failed.

24

*/

25

@Override

26

T get();

27

}

28

```

29

30

**Usage Examples:**

31

32

```java

33

// Custom provider implementation

34

public class DatabaseConnectionProvider implements Provider<DatabaseConnection> {

35

private final String connectionUrl;

36

private final int maxRetries;

37

38

@Inject

39

public DatabaseConnectionProvider(

40

@Named("db.url") String connectionUrl,

41

@Named("db.max.retries") int maxRetries

42

) {

43

this.connectionUrl = connectionUrl;

44

this.maxRetries = maxRetries;

45

}

46

47

@Override

48

public DatabaseConnection get() {

49

for (int i = 0; i < maxRetries; i++) {

50

try {

51

return DriverManager.getConnection(connectionUrl);

52

} catch (SQLException e) {

53

if (i == maxRetries - 1) {

54

throw new RuntimeException("Failed to connect after " + maxRetries + " attempts", e);

55

}

56

try {

57

Thread.sleep(1000 * (i + 1)); // Exponential backoff

58

} catch (InterruptedException ie) {

59

Thread.currentThread().interrupt();

60

throw new RuntimeException("Interrupted while retrying connection", ie);

61

}

62

}

63

}

64

throw new RuntimeException("Should never reach here");

65

}

66

}

67

68

// Bind to provider

69

public class DatabaseModule extends AbstractModule {

70

@Override

71

protected void configure() {

72

bind(DatabaseConnection.class).toProvider(DatabaseConnectionProvider.class);

73

}

74

}

75

76

// Inject providers for lazy initialization

77

public class UserRepository {

78

private final Provider<DatabaseConnection> connectionProvider;

79

80

@Inject

81

public UserRepository(Provider<DatabaseConnection> connectionProvider) {

82

this.connectionProvider = connectionProvider;

83

}

84

85

public User findById(String id) {

86

// Connection created only when needed

87

DatabaseConnection conn = connectionProvider.get();

88

return conn.query("SELECT * FROM users WHERE id = ?", id);

89

}

90

}

91

```

92

93

### Scope Interface

94

95

Strategy for controlling instance lifecycle and reuse.

96

97

```java { .api }

98

/**

99

* A scope is a level of visibility that instances provided by Guice may have.

100

* By default, an instance created by the Injector has no scope, meaning it is

101

* created each time it is needed.

102

*/

103

public interface Scope {

104

/**

105

* Scopes a provider. The returned provider returns objects from this scope.

106

* If an object does not exist in this scope, the provider can use the given

107

* unscoped provider to retrieve one.

108

* @param key Key identifying the binding

109

* @param unscoped Provider to use when no scoped instance exists

110

* @return Scoped provider

111

*/

112

<T> Provider<T> scope(Key<T> key, Provider<T> unscoped);

113

114

/**

115

* Returns a string representation of this scope. Used for error messages.

116

* @return String representation

117

*/

118

String toString();

119

}

120

```

121

122

### Scopes Class

123

124

Built-in scope implementations.

125

126

```java { .api }

127

/**

128

* Built-in scope instances.

129

*/

130

public final class Scopes {

131

/**

132

* One instance per Injector. Also see @Singleton.

133

*/

134

public static final Scope SINGLETON = new SingletonScope();

135

136

/**

137

* No scoping; instances are created every time they're requested.

138

*/

139

public static final Scope NO_SCOPE = new NoScope();

140

141

/**

142

* Returns true if the given scope is a singleton scope.

143

* @param scope Scope to check

144

* @return true if singleton scope

145

*/

146

public static boolean isSingleton(Scope scope);

147

}

148

```

149

150

**Usage Examples:**

151

152

```java

153

// Using built-in scopes

154

public class ServiceModule extends AbstractModule {

155

@Override

156

protected void configure() {

157

// Singleton scope - one instance per injector

158

bind(DatabaseConnectionPool.class).in(Scopes.SINGLETON);

159

bind(Configuration.class).in(Singleton.class); // Equivalent

160

161

// No scope - new instance every time

162

bind(RequestHandler.class).in(Scopes.NO_SCOPE);

163

164

// Default is no scope, so this is equivalent:

165

bind(RequestHandler.class);

166

}

167

}

168

```

169

170

### Custom Scope Implementation

171

172

```java

173

// Custom scope example: Request scope for web applications

174

public class RequestScope implements Scope {

175

private final ThreadLocal<Map<Key<?>, Object>> requestScopedObjects =

176

new ThreadLocal<Map<Key<?>, Object>>();

177

178

public void enter() {

179

requestScopedObjects.set(new HashMap<Key<?>, Object>());

180

}

181

182

public void exit() {

183

requestScopedObjects.remove();

184

}

185

186

@Override

187

public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {

188

return () -> {

189

Map<Key<?>, Object> scopedObjects = requestScopedObjects.get();

190

if (scopedObjects == null) {

191

throw new OutOfScopeException("Cannot access " + key + " outside of request scope");

192

}

193

194

@SuppressWarnings("unchecked")

195

T current = (T) scopedObjects.get(key);

196

if (current == null) {

197

current = unscoped.get();

198

scopedObjects.put(key, current);

199

}

200

return current;

201

};

202

}

203

204

@Override

205

public String toString() {

206

return "RequestScope";

207

}

208

}

209

210

// Custom scope annotation

211

@ScopeAnnotation

212

@Target({TYPE, METHOD})

213

@Retention(RUNTIME)

214

public @interface RequestScoped {}

215

216

// Register custom scope

217

public class WebModule extends AbstractModule {

218

private final RequestScope requestScope = new RequestScope();

219

220

@Override

221

protected void configure() {

222

bindScope(RequestScoped.class, requestScope);

223

224

// Bind request-scoped objects

225

bind(UserSession.class).in(RequestScoped.class);

226

bind(RequestContext.class).in(RequestScoped.class);

227

}

228

229

@Provides

230

@Exposed

231

RequestScope provideRequestScope() {

232

return requestScope;

233

}

234

}

235

236

// Use custom scope

237

@RequestScoped

238

public class UserSession {

239

private String userId;

240

private long startTime;

241

242

@Inject

243

public UserSession() {

244

this.startTime = System.currentTimeMillis();

245

}

246

247

// Session methods

248

}

249

```

250

251

## Provider Utilities

252

253

### Providers Class

254

255

Static utilities for creating Provider instances.

256

257

```java { .api }

258

/**

259

* Static utility methods for creating and working with Provider instances.

260

*/

261

public final class Providers {

262

/**

263

* Returns a provider that always provides the same instance.

264

* @param instance Instance to provide

265

* @return Provider that returns the instance

266

*/

267

public static <T> Provider<T> of(T instance);

268

269

/**

270

* Converts a JSR-330 Provider to a Guice Provider.

271

* @param provider JSR-330 provider

272

* @return Guice provider

273

*/

274

public static <T> Provider<T> guicify(javax.inject.Provider<T> provider);

275

}

276

```

277

278

**Usage Examples:**

279

280

```java

281

// Create providers for constant values

282

Provider<String> appNameProvider = Providers.of("MyApplication");

283

Provider<Integer> versionProvider = Providers.of(42);

284

285

// Use in bindings

286

public class ConstantModule extends AbstractModule {

287

@Override

288

protected void configure() {

289

bind(String.class).annotatedWith(Names.named("app.name"))

290

.toProvider(Providers.of("MyApplication"));

291

bind(Integer.class).annotatedWith(Names.named("app.version"))

292

.toProvider(Providers.of(2));

293

}

294

}

295

296

// Convert JSR-330 providers

297

javax.inject.Provider<DatabaseService> jsr330Provider = () -> new DatabaseServiceImpl();

298

Provider<DatabaseService> guiceProvider = Providers.guicify(jsr330Provider);

299

```

300

301

## Advanced Provider Patterns

302

303

### Conditional Providers

304

305

```java

306

public class ConditionalDatabaseProvider implements Provider<DatabaseService> {

307

private final String environment;

308

private final Provider<ProductionDatabase> prodProvider;

309

private final Provider<TestDatabase> testProvider;

310

311

@Inject

312

public ConditionalDatabaseProvider(

313

@Named("environment") String environment,

314

Provider<ProductionDatabase> prodProvider,

315

Provider<TestDatabase> testProvider

316

) {

317

this.environment = environment;

318

this.prodProvider = prodProvider;

319

this.testProvider = testProvider;

320

}

321

322

@Override

323

public DatabaseService get() {

324

if ("production".equals(environment)) {

325

return prodProvider.get();

326

} else {

327

return testProvider.get();

328

}

329

}

330

}

331

```

332

333

### Caching Providers

334

335

```java

336

public class CachingProvider<T> implements Provider<T> {

337

private final Provider<T> delegate;

338

private volatile T instance;

339

340

public CachingProvider(Provider<T> delegate) {

341

this.delegate = delegate;

342

}

343

344

@Override

345

public T get() {

346

if (instance == null) {

347

synchronized (this) {

348

if (instance == null) {

349

instance = delegate.get();

350

}

351

}

352

}

353

return instance;

354

}

355

}

356

```

357

358

### Resource Management Providers

359

360

```java

361

public class ManagedResourceProvider implements Provider<DatabaseConnection> {

362

private final String connectionUrl;

363

private final Set<DatabaseConnection> activeConnections = new ConcurrentHashMap<>();

364

365

@Inject

366

public ManagedResourceProvider(@Named("db.url") String connectionUrl) {

367

this.connectionUrl = connectionUrl;

368

369

// Register shutdown hook to clean up connections

370

Runtime.getRuntime().addShutdownHook(new Thread(this::cleanup));

371

}

372

373

@Override

374

public DatabaseConnection get() {

375

try {

376

DatabaseConnection conn = DriverManager.getConnection(connectionUrl);

377

activeConnections.add(conn);

378

return conn;

379

} catch (SQLException e) {

380

throw new RuntimeException("Failed to create database connection", e);

381

}

382

}

383

384

private void cleanup() {

385

for (DatabaseConnection conn : activeConnections) {

386

try {

387

conn.close();

388

} catch (SQLException e) {

389

// Log error but continue cleanup

390

}

391

}

392

activeConnections.clear();

393

}

394

}

395

```

396

397

## Exception Types

398

399

### OutOfScopeException

400

401

Thrown when accessing scoped objects outside their scope.

402

403

```java { .api }

404

/**

405

* Thrown when an attempt is made to access a scoped object when the scope

406

* in question is not currently active.

407

*/

408

public class OutOfScopeException extends RuntimeException {

409

/**

410

* Creates a new OutOfScopeException.

411

* @param message Error message

412

*/

413

public OutOfScopeException(String message);

414

415

/**

416

* Creates a new OutOfScopeException.

417

* @param message Error message

418

* @param cause Underlying cause

419

*/

420

public OutOfScopeException(String message, Throwable cause);

421

}