0
# Service Provider Interface (SPI)
1
2
Extension points for container integration, component management, request scoping, validation, and lifecycle management. The SPI system enables deep customization of Jersey server behavior and integration with external frameworks and containers.
3
4
## Capabilities
5
6
### Container Management
7
8
Core interfaces for integrating Jersey with various container environments and managing container lifecycle.
9
10
```java { .api }
11
/**
12
* Jersey container interface providing lifecycle management and configuration access.
13
*/
14
public interface Container {
15
16
/**
17
* Reload the container with current configuration.
18
*/
19
void reload();
20
21
/**
22
* Reload the container with new configuration.
23
* @param configuration New ResourceConfig to apply
24
*/
25
void reload(ResourceConfig configuration);
26
27
/**
28
* Get the application handler for request processing.
29
* @return ApplicationHandler instance
30
*/
31
ApplicationHandler getApplicationHandler();
32
33
/**
34
* Get the current container configuration.
35
* @return ResourceConfig for this container
36
*/
37
ResourceConfig getConfiguration();
38
}
39
40
/**
41
* Container provider SPI for creating container instances.
42
*/
43
public interface ContainerProvider {
44
45
/**
46
* Create a container instance of specified type.
47
* @param type Container type to create
48
* @param application JAX-RS application
49
* @return Container instance of requested type or null if not supported
50
*/
51
<T> T createContainer(Class<T> type, Application application);
52
}
53
54
/**
55
* Container lifecycle listener for monitoring container events.
56
*/
57
public interface ContainerLifecycleListener {
58
59
/**
60
* Called when container is started.
61
* @param container Container that was started
62
*/
63
void onStartup(Container container);
64
65
/**
66
* Called when container is reloaded.
67
* @param container Container that was reloaded
68
*/
69
void onReload(Container container);
70
71
/**
72
* Called when container is shut down.
73
* @param container Container that was shut down
74
*/
75
void onShutdown(Container container);
76
}
77
78
/**
79
* Container response writer for writing HTTP responses.
80
*/
81
public interface ContainerResponseWriter {
82
83
/**
84
* Write response headers and status.
85
* @param contentLength Content length or -1 if unknown
86
* @param containerResponse Response to write
87
* @return OutputStream for writing response entity
88
*/
89
OutputStream writeResponseStatusAndHeaders(long contentLength, ContainerResponse containerResponse);
90
91
/**
92
* Suspend the response writer for asynchronous processing.
93
* @param timeOut Timeout value
94
* @param timeUnit Time unit for timeout
95
* @param timeoutHandler Handler called on timeout
96
* @return true if successfully suspended
97
*/
98
boolean suspend(long timeOut, TimeUnit timeUnit, TimeoutHandler timeoutHandler);
99
100
/**
101
* Set suspend timeout handler.
102
* @param timeoutHandler Handler for timeout events
103
*/
104
void setSuspendTimeout(long time, TimeUnit timeUnit);
105
106
/**
107
* Commit the response (make it immutable).
108
*/
109
void commit();
110
111
/**
112
* Enable response buffering if supported.
113
* @return true if buffering was enabled
114
*/
115
boolean enableResponseBuffering();
116
117
/**
118
* Failure callback called when response writing fails.
119
* @param error Error that occurred
120
*/
121
void failure(Throwable error);
122
}
123
```
124
125
**Usage Examples:**
126
127
```java
128
import org.glassfish.jersey.server.spi.*;
129
import org.glassfish.jersey.server.ApplicationHandler;
130
import org.glassfish.jersey.server.ResourceConfig;
131
132
// Custom container implementation
133
public class CustomContainer implements Container {
134
135
private ApplicationHandler applicationHandler;
136
private ResourceConfig configuration;
137
private final List<ContainerLifecycleListener> listeners = new ArrayList<>();
138
139
public CustomContainer(ResourceConfig config) {
140
this.configuration = config;
141
this.applicationHandler = new ApplicationHandler(config);
142
143
// Notify startup
144
for (ContainerLifecycleListener listener : listeners) {
145
listener.onStartup(this);
146
}
147
}
148
149
@Override
150
public void reload() {
151
reload(this.configuration);
152
}
153
154
@Override
155
public void reload(ResourceConfig configuration) {
156
this.configuration = configuration;
157
this.applicationHandler = new ApplicationHandler(configuration);
158
159
// Notify reload
160
for (ContainerLifecycleListener listener : listeners) {
161
listener.onReload(this);
162
}
163
}
164
165
@Override
166
public ApplicationHandler getApplicationHandler() {
167
return applicationHandler;
168
}
169
170
@Override
171
public ResourceConfig getConfiguration() {
172
return configuration;
173
}
174
175
public void addLifecycleListener(ContainerLifecycleListener listener) {
176
listeners.add(listener);
177
}
178
179
public void shutdown() {
180
for (ContainerLifecycleListener listener : listeners) {
181
listener.onShutdown(this);
182
}
183
}
184
}
185
186
// Custom container provider
187
public class CustomContainerProvider implements ContainerProvider {
188
189
@Override
190
public <T> T createContainer(Class<T> type, Application application) {
191
if (type == CustomContainer.class) {
192
ResourceConfig config = ResourceConfig.forApplication(application);
193
return type.cast(new CustomContainer(config));
194
}
195
return null; // Type not supported
196
}
197
}
198
```
199
200
### Component Management
201
202
SPI for custom component providers and dependency injection integration.
203
204
```java { .api }
205
/**
206
* Server-side component provider extending the base ComponentProvider.
207
* Enables custom dependency injection and component management.
208
*/
209
public interface ComponentProvider extends org.glassfish.jersey.spi.ComponentProvider {
210
211
/**
212
* Initialize the component provider with injection manager.
213
* @param injectionManager Injection manager instance
214
*/
215
void initialize(InjectionManager injectionManager);
216
217
/**
218
* Bind components and services.
219
* @param injectionManager Injection manager for binding
220
*/
221
void bind(InjectionManager injectionManager);
222
223
/**
224
* Called when component provider is being shut down.
225
* @param injectionManager Injection manager instance
226
*/
227
void done(InjectionManager injectionManager);
228
}
229
```
230
231
### Request Scope Management
232
233
External request scope management for integrating with external scoping mechanisms.
234
235
```java { .api }
236
/**
237
* External request scope interface for custom request scoping.
238
* Extends AutoCloseable for proper resource management.
239
*/
240
public interface ExternalRequestScope<T> extends AutoCloseable {
241
242
/**
243
* Open a new request scope context.
244
* @return ExternalRequestContext for the opened scope
245
*/
246
ExternalRequestContext<T> open();
247
248
/**
249
* Close the request scope and clean up resources.
250
*/
251
@Override
252
void close();
253
}
254
255
/**
256
* External request context representing an active request scope.
257
*/
258
public static class ExternalRequestContext<T> {
259
260
/**
261
* Create external request context.
262
* @param scopeInstance Scope instance
263
*/
264
public ExternalRequestContext(T scopeInstance);
265
266
/**
267
* Get the scope instance.
268
* @return Scope instance
269
*/
270
public T getInstance();
271
272
/**
273
* Release the context and associated resources.
274
*/
275
public void release();
276
}
277
278
/**
279
* Request scoped initializer for custom initialization logic.
280
*/
281
public interface RequestScopedInitializer {
282
283
/**
284
* Initialize request-scoped components.
285
* @param injectionManager Injection manager instance
286
*/
287
void initialize(InjectionManager injectionManager);
288
}
289
```
290
291
**Usage Examples:**
292
293
```java
294
import org.glassfish.jersey.server.spi.ExternalRequestScope;
295
import org.glassfish.jersey.server.spi.ExternalRequestContext;
296
import org.glassfish.jersey.server.spi.RequestScopedInitializer;
297
298
// Custom external request scope implementation
299
public class CustomRequestScope implements ExternalRequestScope<CustomScopeData> {
300
301
private final ThreadLocal<CustomScopeData> scopeData = new ThreadLocal<>();
302
303
@Override
304
public ExternalRequestContext<CustomScopeData> open() {
305
CustomScopeData data = new CustomScopeData();
306
scopeData.set(data);
307
return new ExternalRequestContext<>(data);
308
}
309
310
@Override
311
public void close() {
312
scopeData.remove();
313
}
314
315
public CustomScopeData getCurrentScope() {
316
return scopeData.get();
317
}
318
}
319
320
// Custom request-scoped initializer
321
public class CustomRequestScopedInitializer implements RequestScopedInitializer {
322
323
@Override
324
public void initialize(InjectionManager injectionManager) {
325
// Initialize request-scoped components
326
injectionManager.register(new AbstractBinder() {
327
@Override
328
protected void configure() {
329
bindFactory(CustomRequestScopedFactory.class)
330
.to(CustomService.class)
331
.in(RequestScoped.class);
332
}
333
});
334
}
335
}
336
337
// Usage in resource
338
@Path("/scoped")
339
public class ScopedResource {
340
341
@Inject
342
private CustomRequestScope requestScope;
343
344
@GET
345
public String getScopedData() {
346
try (ExternalRequestContext<CustomScopeData> context = requestScope.open()) {
347
CustomScopeData data = context.getInstance();
348
return "Scoped data: " + data.getValue();
349
}
350
}
351
}
352
```
353
354
### Validation Integration
355
356
SPI for custom validation interceptors and validation framework integration.
357
358
```java { .api }
359
/**
360
* Validation interceptor SPI for custom validation logic.
361
*/
362
public interface ValidationInterceptor {
363
364
/**
365
* Called before validation occurs.
366
* @param context Validation context
367
*/
368
void onValidate(ValidationInterceptorContext context);
369
}
370
371
/**
372
* Validation interceptor context providing access to validation information.
373
*/
374
public interface ValidationInterceptorContext {
375
376
/**
377
* Get the object being validated.
378
* @return Object to validate
379
*/
380
Object getValidatedObject();
381
382
/**
383
* Get the validation groups.
384
* @return Array of validation groups
385
*/
386
Class<?>[] getGroups();
387
388
/**
389
* Get the resource method being validated.
390
* @return ResourceMethod instance
391
*/
392
ResourceMethod getResourceMethod();
393
394
/**
395
* Get validation constraint violations.
396
* @return Set of constraint violations
397
*/
398
Set<ConstraintViolation<Object>> getConstraintViolations();
399
400
/**
401
* Set validation constraint violations.
402
* @param violations Set of violations to set
403
*/
404
void setConstraintViolations(Set<ConstraintViolation<Object>> violations);
405
}
406
```
407
408
### Error Handling
409
410
SPI for custom error mapping and response error handling.
411
412
```java { .api }
413
/**
414
* Response error mapper SPI for custom error handling.
415
*/
416
public interface ResponseErrorMapper {
417
418
/**
419
* Map an error to a response.
420
* @param error Error to map
421
* @param context Request context
422
* @return Response for the error or null to use default handling
423
*/
424
Response toResponse(Throwable error, ContainerRequest context);
425
426
/**
427
* Check if this mapper can handle the given error type.
428
* @param errorType Error type to check
429
* @return true if this mapper can handle the error type
430
*/
431
boolean isMappable(Class<? extends Throwable> errorType);
432
}
433
```
434
435
### Web Server Integration
436
437
SPI for integrating Jersey with various web server implementations.
438
439
```java { .api }
440
/**
441
* Web server interface for Jersey integration.
442
*/
443
public interface WebServer {
444
445
/**
446
* Start the web server.
447
*/
448
void start();
449
450
/**
451
* Stop the web server.
452
*/
453
void stop();
454
455
/**
456
* Get server port.
457
* @return Server port number
458
*/
459
int getPort();
460
461
/**
462
* Check if server is running.
463
* @return true if server is running
464
*/
465
boolean isRunning();
466
}
467
468
/**
469
* Web server provider SPI for creating web server instances.
470
*/
471
public interface WebServerProvider {
472
473
/**
474
* Create a web server instance.
475
* @param application JAX-RS application
476
* @param configuration Server configuration
477
* @return WebServer instance or null if not supported
478
*/
479
WebServer createServer(Application application, Map<String, Object> configuration);
480
481
/**
482
* Get the server type name.
483
* @return Server type identifier
484
*/
485
String getServerType();
486
}
487
```
488
489
**Usage Examples:**
490
491
```java
492
import org.glassfish.jersey.server.spi.WebServer;
493
import org.glassfish.jersey.server.spi.WebServerProvider;
494
495
// Custom web server implementation
496
public class CustomWebServer implements WebServer {
497
498
private final Application application;
499
private final int port;
500
private boolean running = false;
501
502
public CustomWebServer(Application application, int port) {
503
this.application = application;
504
this.port = port;
505
}
506
507
@Override
508
public void start() {
509
if (!running) {
510
// Start server implementation
511
startServerImplementation();
512
running = true;
513
}
514
}
515
516
@Override
517
public void stop() {
518
if (running) {
519
// Stop server implementation
520
stopServerImplementation();
521
running = false;
522
}
523
}
524
525
@Override
526
public int getPort() {
527
return port;
528
}
529
530
@Override
531
public boolean isRunning() {
532
return running;
533
}
534
}
535
536
// Custom web server provider
537
public class CustomWebServerProvider implements WebServerProvider {
538
539
@Override
540
public WebServer createServer(Application application, Map<String, Object> configuration) {
541
Integer port = (Integer) configuration.get("server.port");
542
if (port == null) {
543
port = 8080; // Default port
544
}
545
546
return new CustomWebServer(application, port);
547
}
548
549
@Override
550
public String getServerType() {
551
return "custom";
552
}
553
}
554
555
// Usage
556
public class ServerLauncher {
557
558
public static void main(String[] args) {
559
ResourceConfig config = new ResourceConfig()
560
.packages("com.example.resources");
561
562
Map<String, Object> serverConfig = new HashMap<>();
563
serverConfig.put("server.port", 9090);
564
565
CustomWebServerProvider provider = new CustomWebServerProvider();
566
WebServer server = provider.createServer(config, serverConfig);
567
568
server.start();
569
System.out.println("Server started on port " + server.getPort());
570
571
// Shutdown hook
572
Runtime.getRuntime().addShutdownHook(new Thread(server::stop));
573
}
574
}
575
```