or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-api.mdcore-types.mdextensions.mdindex.mdresource-endpoints.mdserver-container.mdserver-sent-events.md

extensions.mddocs/

0

# Extensions

1

2

The JAX-RS extension APIs provide customization points for message body processing, parameter conversion, exception handling, and context resolution. These provider interfaces enable deep integration with JAX-RS runtime for serialization, custom parameter types, error handling, and dependency injection.

3

4

## Core Imports

5

6

```java

7

import javax.ws.rs.ext.Provider;

8

import javax.ws.rs.ext.MessageBodyReader;

9

import javax.ws.rs.ext.MessageBodyWriter;

10

import javax.ws.rs.ext.ReaderInterceptor;

11

import javax.ws.rs.ext.ReaderInterceptorContext;

12

import javax.ws.rs.ext.WriterInterceptor;

13

import javax.ws.rs.ext.WriterInterceptorContext;

14

import javax.ws.rs.ext.InterceptorContext;

15

16

import javax.ws.rs.ext.ExceptionMapper;

17

import javax.ws.rs.ext.ParamConverter;

18

import javax.ws.rs.ext.ParamConverterProvider;

19

import javax.ws.rs.ext.ContextResolver;

20

import javax.ws.rs.ext.Providers;

21

import javax.ws.rs.ext.RuntimeDelegate;

22

23

import javax.ws.rs.NameBinding;

24

import javax.ws.rs.Priorities;

25

import javax.annotation.Priority;

26

27

import javax.ws.rs.core.MediaType;

28

import javax.ws.rs.core.MultivaluedMap;

29

import javax.ws.rs.WebApplicationException;

30

31

import java.io.IOException;

32

import java.io.InputStream;

33

import java.io.OutputStream;

34

import java.lang.annotation.Annotation;

35

import java.lang.reflect.Type;

36

```

37

38

## Provider Registration

39

40

### @Provider Annotation

41

42

Marks an implementation of an extension interface for automatic discovery.

43

44

```java { .api }

45

@Target({ElementType.TYPE})

46

@Retention(RetentionPolicy.RUNTIME)

47

@Documented

48

public @interface Provider {

49

}

50

```

51

52

**Provider Registration Example:**

53

54

```java

55

// Automatic registration via @Provider

56

@Provider

57

public class CustomJsonProvider implements MessageBodyWriter<Object>, MessageBodyReader<Object> {

58

// Implementation...

59

}

60

61

// Programmatic registration

62

public class MyApplication extends Application {

63

64

@Override

65

public Set<Class<?>> getClasses() {

66

return Set.of(

67

UserResource.class,

68

CustomJsonProvider.class,

69

CustomExceptionMapper.class

70

);

71

}

72

}

73

74

// Client-side registration

75

Client client = ClientBuilder.newClient()

76

.register(CustomJsonProvider.class)

77

.register(LoggingFilter.class);

78

```

79

80

### @NameBinding Annotation

81

82

Meta-annotation for creating name binding annotations that selectively bind filters and interceptors to specific resource methods or classes.

83

84

```java { .api }

85

@Target({ElementType.ANNOTATION_TYPE})

86

@Retention(RetentionPolicy.RUNTIME)

87

@Documented

88

public @interface NameBinding {

89

}

90

```

91

92

**Name Binding Usage Example:**

93

94

```java

95

// Create a custom name binding annotation

96

@NameBinding

97

@Target({ElementType.TYPE, ElementType.METHOD})

98

@Retention(RetentionPolicy.RUNTIME)

99

public @interface Authenticated {

100

}

101

102

// Use name binding on resource methods

103

@Path("/users")

104

public class UserResource {

105

106

@GET

107

@Path("/public")

108

public Response getPublicInfo() {

109

// No authentication required

110

return Response.ok("Public information").build();

111

}

112

113

@GET

114

@Path("/private")

115

@Authenticated // This method requires authentication

116

public Response getPrivateInfo() {

117

return Response.ok("Private information").build();

118

}

119

}

120

121

// Create a filter bound to the name binding

122

@Provider

123

@Authenticated // Only applies to methods/classes annotated with @Authenticated

124

@Priority(Priorities.AUTHENTICATION)

125

public class AuthenticationFilter implements ContainerRequestFilter {

126

127

@Override

128

public void filter(ContainerRequestContext requestContext) throws IOException {

129

String authHeader = requestContext.getHeaderString("Authorization");

130

if (authHeader == null || !isValidToken(authHeader)) {

131

requestContext.abortWith(

132

Response.status(Response.Status.UNAUTHORIZED).build()

133

);

134

}

135

}

136

137

private boolean isValidToken(String token) {

138

// Token validation logic

139

return token.startsWith("Bearer ") && token.length() > 7;

140

}

141

}

142

```

143

144

### @Priority and Priorities

145

146

Control the execution order of filters and interceptors.

147

148

```java { .api }

149

@Target({ElementType.TYPE, ElementType.PARAMETER})

150

@Retention(RetentionPolicy.RUNTIME)

151

@Documented

152

public @interface Priority {

153

int value();

154

}

155

156

public final class Priorities {

157

public static final int AUTHENTICATION = 1000;

158

public static final int AUTHORIZATION = 2000;

159

public static final int HEADER_DECORATOR = 3000;

160

public static final int ENTITY_CODER = 4000;

161

public static final int USER = 5000;

162

}

163

```

164

165

## Message Body Processing

166

167

### MessageBodyReader Interface

168

169

Converts input streams to Java objects.

170

171

```java { .api }

172

@Provider

173

public interface MessageBodyReader<T> {

174

175

boolean isReadable(Class<?> type, Type genericType,

176

Annotation[] annotations, MediaType mediaType);

177

178

T readFrom(Class<T> type, Type genericType, Annotation[] annotations,

179

MediaType mediaType, MultivaluedMap<String, String> httpHeaders,

180

InputStream entityStream) throws IOException, WebApplicationException;

181

}

182

```

183

184

### MessageBodyWriter Interface

185

186

Converts Java objects to output streams.

187

188

```java { .api }

189

@Provider

190

public interface MessageBodyWriter<T> {

191

192

boolean isWriteable(Class<?> type, Type genericType,

193

Annotation[] annotations, MediaType mediaType);

194

195

long getSize(T t, Class<?> type, Type genericType, Annotation[] annotations,

196

MediaType mediaType);

197

198

void writeTo(T t, Class<?> type, Type genericType, Annotation[] annotations,

199

MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,

200

OutputStream entityStream) throws IOException, WebApplicationException;

201

}

202

```

203

204

**Message Body Provider Examples:**

205

206

```java

207

// Custom JSON provider using Jackson

208

@Provider

209

@Consumes(MediaType.APPLICATION_JSON)

210

@Produces(MediaType.APPLICATION_JSON)

211

public class JacksonJsonProvider implements MessageBodyReader<Object>, MessageBodyWriter<Object> {

212

213

private final ObjectMapper objectMapper = new ObjectMapper();

214

215

@Override

216

public boolean isReadable(Class<?> type, Type genericType,

217

Annotation[] annotations, MediaType mediaType) {

218

return mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE);

219

}

220

221

@Override

222

public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations,

223

MediaType mediaType, MultivaluedMap<String, String> httpHeaders,

224

InputStream entityStream) throws IOException {

225

226

try {

227

if (genericType != null) {

228

JavaType javaType = objectMapper.getTypeFactory().constructType(genericType);

229

return objectMapper.readValue(entityStream, javaType);

230

} else {

231

return objectMapper.readValue(entityStream, type);

232

}

233

} catch (JsonProcessingException e) {

234

throw new WebApplicationException("Invalid JSON", Response.Status.BAD_REQUEST);

235

}

236

}

237

238

@Override

239

public boolean isWriteable(Class<?> type, Type genericType,

240

Annotation[] annotations, MediaType mediaType) {

241

return mediaType.isCompatible(MediaType.APPLICATION_JSON_TYPE);

242

}

243

244

@Override

245

public long getSize(Object t, Class<?> type, Type genericType,

246

Annotation[] annotations, MediaType mediaType) {

247

return -1; // Unknown size

248

}

249

250

@Override

251

public void writeTo(Object t, Class<?> type, Type genericType, Annotation[] annotations,

252

MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,

253

OutputStream entityStream) throws IOException {

254

255

objectMapper.writeValue(entityStream, t);

256

}

257

}

258

259

// CSV provider for specific types

260

@Provider

261

@Consumes("text/csv")

262

@Produces("text/csv")

263

public class CsvProvider implements MessageBodyReader<List<User>>, MessageBodyWriter<List<User>> {

264

265

@Override

266

public boolean isReadable(Class<?> type, Type genericType,

267

Annotation[] annotations, MediaType mediaType) {

268

return List.class.isAssignableFrom(type) &&

269

genericType instanceof ParameterizedType &&

270

((ParameterizedType) genericType).getActualTypeArguments()[0] == User.class;

271

}

272

273

@Override

274

public List<User> readFrom(Class<List<User>> type, Type genericType,

275

Annotation[] annotations, MediaType mediaType,

276

MultivaluedMap<String, String> httpHeaders,

277

InputStream entityStream) throws IOException {

278

279

List<User> users = new ArrayList<>();

280

try (BufferedReader reader = new BufferedReader(new InputStreamReader(entityStream))) {

281

String line;

282

boolean firstLine = true;

283

while ((line = reader.readLine()) != null) {

284

if (firstLine) {

285

firstLine = false; // Skip header

286

continue;

287

}

288

String[] parts = line.split(",");

289

users.add(new User(parts[0], parts[1]));

290

}

291

}

292

return users;

293

}

294

295

@Override

296

public boolean isWriteable(Class<?> type, Type genericType,

297

Annotation[] annotations, MediaType mediaType) {

298

return isReadable(type, genericType, annotations, mediaType);

299

}

300

301

@Override

302

public long getSize(List<User> users, Class<?> type, Type genericType,

303

Annotation[] annotations, MediaType mediaType) {

304

return -1;

305

}

306

307

@Override

308

public void writeTo(List<User> users, Class<?> type, Type genericType,

309

Annotation[] annotations, MediaType mediaType,

310

MultivaluedMap<String, Object> httpHeaders,

311

OutputStream entityStream) throws IOException {

312

313

try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(entityStream))) {

314

writer.println("name,email"); // Header

315

for (User user : users) {

316

writer.printf("%s,%s%n", user.getName(), user.getEmail());

317

}

318

}

319

}

320

}

321

322

// Binary data provider

323

@Provider

324

@Consumes(MediaType.APPLICATION_OCTET_STREAM)

325

@Produces(MediaType.APPLICATION_OCTET_STREAM)

326

public class BinaryDataProvider implements MessageBodyReader<byte[]>, MessageBodyWriter<byte[]> {

327

328

@Override

329

public boolean isReadable(Class<?> type, Type genericType,

330

Annotation[] annotations, MediaType mediaType) {

331

return byte[].class == type;

332

}

333

334

@Override

335

public byte[] readFrom(Class<byte[]> type, Type genericType, Annotation[] annotations,

336

MediaType mediaType, MultivaluedMap<String, String> httpHeaders,

337

InputStream entityStream) throws IOException {

338

339

return entityStream.readAllBytes();

340

}

341

342

@Override

343

public boolean isWriteable(Class<?> type, Type genericType,

344

Annotation[] annotations, MediaType mediaType) {

345

return byte[].class == type;

346

}

347

348

@Override

349

public long getSize(byte[] data, Class<?> type, Type genericType,

350

Annotation[] annotations, MediaType mediaType) {

351

return data.length;

352

}

353

354

@Override

355

public void writeTo(byte[] data, Class<?> type, Type genericType, Annotation[] annotations,

356

MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,

357

OutputStream entityStream) throws IOException {

358

359

entityStream.write(data);

360

}

361

}

362

```

363

364

## Message Body Interceptors

365

366

### InterceptorContext Interface

367

368

Base context for interceptor operations.

369

370

```java { .api }

371

public interface InterceptorContext {

372

373

Object getProperty(String name);

374

Collection<String> getPropertyNames();

375

void setProperty(String name, Object object);

376

void removeProperty(String name);

377

378

Annotation[] getAnnotations();

379

void setAnnotations(Annotation[] annotations);

380

381

Class<?> getType();

382

void setType(Class<?> type);

383

384

Type getGenericType();

385

void setGenericType(Type genericType);

386

387

MediaType getMediaType();

388

void setMediaType(MediaType mediaType);

389

}

390

```

391

392

### ReaderInterceptor and WriterInterceptor Interfaces

393

394

```java { .api }

395

@Provider

396

public interface ReaderInterceptor {

397

398

Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException;

399

}

400

401

public interface ReaderInterceptorContext extends InterceptorContext {

402

403

Object proceed() throws IOException, WebApplicationException;

404

InputStream getInputStream();

405

void setInputStream(InputStream is);

406

MultivaluedMap<String, String> getHeaders();

407

}

408

409

@Provider

410

public interface WriterInterceptor {

411

412

void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException;

413

}

414

415

public interface WriterInterceptorContext extends InterceptorContext {

416

417

void proceed() throws IOException, WebApplicationException;

418

Object getEntity();

419

void setEntity(Object entity);

420

OutputStream getOutputStream();

421

void setOutputStream(OutputStream os);

422

MultivaluedMap<String, Object> getHeaders();

423

}

424

```

425

426

**Interceptor Examples:**

427

428

```java

429

// Compression reader interceptor

430

@Provider

431

@Priority(Priorities.ENTITY_CODER)

432

public class GZipReaderInterceptor implements ReaderInterceptor {

433

434

@Override

435

public Object aroundReadFrom(ReaderInterceptorContext context)

436

throws IOException, WebApplicationException {

437

438

MultivaluedMap<String, String> headers = context.getHeaders();

439

String contentEncoding = headers.getFirst("Content-Encoding");

440

441

if ("gzip".equals(contentEncoding)) {

442

InputStream originalStream = context.getInputStream();

443

context.setInputStream(new GZIPInputStream(originalStream));

444

}

445

446

return context.proceed();

447

}

448

}

449

450

// Compression writer interceptor

451

@Provider

452

@Priority(Priorities.ENTITY_CODER)

453

public class GZipWriterInterceptor implements WriterInterceptor {

454

455

@Override

456

public void aroundWriteTo(WriterInterceptorContext context)

457

throws IOException, WebApplicationException {

458

459

MultivaluedMap<String, Object> headers = context.getHeaders();

460

String acceptEncoding = (String) headers.getFirst("Accept-Encoding");

461

462

if (acceptEncoding != null && acceptEncoding.contains("gzip")) {

463

headers.putSingle("Content-Encoding", "gzip");

464

465

OutputStream originalStream = context.getOutputStream();

466

GZIPOutputStream gzipStream = new GZIPOutputStream(originalStream);

467

context.setOutputStream(gzipStream);

468

469

try {

470

context.proceed();

471

} finally {

472

gzipStream.finish();

473

}

474

} else {

475

context.proceed();

476

}

477

}

478

}

479

480

// Logging interceptor

481

@Provider

482

public class LoggingInterceptor implements ReaderInterceptor, WriterInterceptor {

483

484

private static final Logger logger = LoggerFactory.getLogger(LoggingInterceptor.class);

485

486

@Override

487

public Object aroundReadFrom(ReaderInterceptorContext context)

488

throws IOException, WebApplicationException {

489

490

logger.info("Reading entity of type: {} with media type: {}",

491

context.getType().getSimpleName(), context.getMediaType());

492

493

long startTime = System.currentTimeMillis();

494

try {

495

return context.proceed();

496

} finally {

497

long duration = System.currentTimeMillis() - startTime;

498

logger.info("Entity reading completed in {}ms", duration);

499

}

500

}

501

502

@Override

503

public void aroundWriteTo(WriterInterceptorContext context)

504

throws IOException, WebApplicationException {

505

506

logger.info("Writing entity of type: {} with media type: {}",

507

context.getType().getSimpleName(), context.getMediaType());

508

509

long startTime = System.currentTimeMillis();

510

try {

511

context.proceed();

512

} finally {

513

long duration = System.currentTimeMillis() - startTime;

514

logger.info("Entity writing completed in {}ms", duration);

515

}

516

}

517

}

518

```

519

520

## Parameter Conversion

521

522

### ParamConverter Interface

523

524

Converts string parameters to Java types.

525

526

```java { .api }

527

public interface ParamConverter<T> {

528

529

T fromString(String value);

530

String toString(T value);

531

}

532

```

533

534

### ParamConverterProvider Interface

535

536

Provider for creating ParamConverter instances.

537

538

```java { .api }

539

@Provider

540

public interface ParamConverterProvider {

541

542

<T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType,

543

Annotation[] annotations);

544

}

545

```

546

547

**Parameter Converter Examples:**

548

549

```java

550

// Date parameter converter

551

public class DateParamConverter implements ParamConverter<Date> {

552

553

private final DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;

554

555

@Override

556

public Date fromString(String value) {

557

if (value == null || value.trim().isEmpty()) {

558

return null;

559

}

560

try {

561

LocalDateTime localDateTime = LocalDateTime.parse(value, formatter);

562

return Date.from(localDateTime.atZone(ZoneOffset.UTC).toInstant());

563

} catch (DateTimeParseException e) {

564

throw new IllegalArgumentException("Invalid date format: " + value, e);

565

}

566

}

567

568

@Override

569

public String toString(Date value) {

570

if (value == null) {

571

return null;

572

}

573

LocalDateTime localDateTime = value.toInstant()

574

.atZone(ZoneOffset.UTC)

575

.toLocalDateTime();

576

return formatter.format(localDateTime);

577

}

578

}

579

580

// UUID parameter converter

581

public class UUIDParamConverter implements ParamConverter<UUID> {

582

583

@Override

584

public UUID fromString(String value) {

585

if (value == null || value.trim().isEmpty()) {

586

return null;

587

}

588

try {

589

return UUID.fromString(value);

590

} catch (IllegalArgumentException e) {

591

throw new IllegalArgumentException("Invalid UUID format: " + value, e);

592

}

593

}

594

595

@Override

596

public String toString(UUID value) {

597

return value != null ? value.toString() : null;

598

}

599

}

600

601

// Parameter converter provider

602

@Provider

603

public class CustomParamConverterProvider implements ParamConverterProvider {

604

605

@Override

606

@SuppressWarnings("unchecked")

607

public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType,

608

Annotation[] annotations) {

609

610

if (rawType == Date.class) {

611

return (ParamConverter<T>) new DateParamConverter();

612

}

613

614

if (rawType == UUID.class) {

615

return (ParamConverter<T>) new UUIDParamConverter();

616

}

617

618

// Custom enum converter

619

if (rawType.isEnum()) {

620

return (ParamConverter<T>) new EnumParamConverter<>((Class<Enum>) rawType);

621

}

622

623

return null; // No converter available

624

}

625

}

626

627

// Generic enum converter

628

public class EnumParamConverter<T extends Enum<T>> implements ParamConverter<T> {

629

630

private final Class<T> enumClass;

631

632

public EnumParamConverter(Class<T> enumClass) {

633

this.enumClass = enumClass;

634

}

635

636

@Override

637

public T fromString(String value) {

638

if (value == null || value.trim().isEmpty()) {

639

return null;

640

}

641

try {

642

return Enum.valueOf(enumClass, value.toUpperCase());

643

} catch (IllegalArgumentException e) {

644

throw new IllegalArgumentException(

645

"Invalid " + enumClass.getSimpleName() + " value: " + value, e);

646

}

647

}

648

649

@Override

650

public String toString(T value) {

651

return value != null ? value.name() : null;

652

}

653

}

654

655

// Usage in resource

656

@Path("/examples")

657

public class ParamConverterExamples {

658

659

@GET

660

@Path("/events")

661

public List<Event> getEvents(@QueryParam("start") Date startDate,

662

@QueryParam("end") Date endDate,

663

@QueryParam("status") EventStatus status,

664

@QueryParam("id") UUID eventId) {

665

666

return eventService.findEvents(startDate, endDate, status, eventId);

667

}

668

}

669

```

670

671

## Exception Handling

672

673

### ExceptionMapper Interface

674

675

Maps Java exceptions to HTTP responses.

676

677

```java { .api }

678

@Provider

679

public interface ExceptionMapper<E extends Throwable> {

680

681

Response toResponse(E exception);

682

}

683

```

684

685

**Exception Mapper Examples:**

686

687

```java

688

// Validation exception mapper

689

@Provider

690

public class ValidationExceptionMapper implements ExceptionMapper<ValidationException> {

691

692

@Override

693

public Response toResponse(ValidationException exception) {

694

695

ErrorResponse error = new ErrorResponse(

696

"VALIDATION_ERROR",

697

"Request validation failed",

698

exception.getErrors()

699

);

700

701

return Response.status(Response.Status.BAD_REQUEST)

702

.entity(error)

703

.type(MediaType.APPLICATION_JSON)

704

.build();

705

}

706

}

707

708

// Generic throwable mapper

709

@Provider

710

public class GeneralExceptionMapper implements ExceptionMapper<Throwable> {

711

712

private static final Logger logger = LoggerFactory.getLogger(GeneralExceptionMapper.class);

713

714

@Override

715

public Response toResponse(Throwable exception) {

716

717

// Log the exception

718

logger.error("Unhandled exception", exception);

719

720

// Don't expose internal details in production

721

ErrorResponse error = new ErrorResponse(

722

"INTERNAL_ERROR",

723

"An internal server error occurred"

724

);

725

726

return Response.status(Response.Status.INTERNAL_SERVER_ERROR)

727

.entity(error)

728

.type(MediaType.APPLICATION_JSON)

729

.build();

730

}

731

}

732

733

// Business exception mapper

734

@Provider

735

public class BusinessExceptionMapper implements ExceptionMapper<BusinessException> {

736

737

@Override

738

public Response toResponse(BusinessException exception) {

739

740

Response.Status status = mapToHttpStatus(exception.getErrorCode());

741

742

ErrorResponse error = new ErrorResponse(

743

exception.getErrorCode(),

744

exception.getMessage(),

745

exception.getDetails()

746

);

747

748

return Response.status(status)

749

.entity(error)

750

.type(MediaType.APPLICATION_JSON)

751

.build();

752

}

753

754

private Response.Status mapToHttpStatus(String errorCode) {

755

switch (errorCode) {

756

case "NOT_FOUND":

757

return Response.Status.NOT_FOUND;

758

case "UNAUTHORIZED":

759

return Response.Status.UNAUTHORIZED;

760

case "FORBIDDEN":

761

return Response.Status.FORBIDDEN;

762

case "CONFLICT":

763

return Response.Status.CONFLICT;

764

default:

765

return Response.Status.BAD_REQUEST;

766

}

767

}

768

}

769

770

// Security exception mapper

771

@Provider

772

public class SecurityExceptionMapper implements ExceptionMapper<SecurityException> {

773

774

@Override

775

public Response toResponse(SecurityException exception) {

776

777

if (exception instanceof AuthenticationException) {

778

return Response.status(Response.Status.UNAUTHORIZED)

779

.header("WWW-Authenticate", "Bearer")

780

.entity("Authentication required")

781

.build();

782

}

783

784

if (exception instanceof AuthorizationException) {

785

return Response.status(Response.Status.FORBIDDEN)

786

.entity("Insufficient privileges")

787

.build();

788

}

789

790

return Response.status(Response.Status.FORBIDDEN)

791

.entity("Access denied")

792

.build();

793

}

794

}

795

796

// Error response model

797

public class ErrorResponse {

798

799

private String code;

800

private String message;

801

private List<String> details;

802

private long timestamp;

803

804

public ErrorResponse(String code, String message) {

805

this(code, message, null);

806

}

807

808

public ErrorResponse(String code, String message, List<String> details) {

809

this.code = code;

810

this.message = message;

811

this.details = details;

812

this.timestamp = System.currentTimeMillis();

813

}

814

815

// Getters and setters...

816

}

817

```

818

819

## Context Resolution

820

821

### ContextResolver Interface

822

823

Provides context information to resource classes and providers.

824

825

```java { .api }

826

@Provider

827

public interface ContextResolver<T> {

828

829

T getContext(Class<?> type);

830

}

831

```

832

833

**Context Resolver Examples:**

834

835

```java

836

// ObjectMapper context resolver for Jackson

837

@Provider

838

@Produces(MediaType.APPLICATION_JSON)

839

public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {

840

841

private final ObjectMapper objectMapper;

842

843

public ObjectMapperContextResolver() {

844

this.objectMapper = new ObjectMapper();

845

846

// Configure mapper

847

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

848

objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

849

objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX"));

850

851

// Register modules

852

objectMapper.registerModule(new JavaTimeModule());

853

}

854

855

@Override

856

public ObjectMapper getContext(Class<?> type) {

857

return objectMapper;

858

}

859

}

860

861

// Database context resolver

862

@Provider

863

public class DatabaseContextResolver implements ContextResolver<EntityManager> {

864

865

@PersistenceContext

866

private EntityManager entityManager;

867

868

@Override

869

public EntityManager getContext(Class<?> type) {

870

return entityManager;

871

}

872

}

873

874

// Configuration context resolver

875

@Provider

876

public class ConfigurationContextResolver implements ContextResolver<AppConfig> {

877

878

private final AppConfig appConfig;

879

880

public ConfigurationContextResolver() {

881

this.appConfig = loadConfiguration();

882

}

883

884

@Override

885

public AppConfig getContext(Class<?> type) {

886

return appConfig;

887

}

888

889

private AppConfig loadConfiguration() {

890

// Load configuration from properties, environment, etc.

891

return new AppConfig();

892

}

893

}

894

895

// Usage in resource or provider

896

@Path("/configured")

897

public class ConfiguredResource {

898

899

@Context

900

private Providers providers;

901

902

@GET

903

public Response getConfiguredResponse() {

904

905

// Get context resolver

906

ContextResolver<AppConfig> resolver =

907

providers.getContextResolver(AppConfig.class, MediaType.APPLICATION_JSON_TYPE);

908

909

if (resolver != null) {

910

AppConfig config = resolver.getContext(AppConfig.class);

911

return Response.ok(config.getSomeValue()).build();

912

}

913

914

return Response.status(Response.Status.SERVICE_UNAVAILABLE).build();

915

}

916

}

917

```

918

919

## Provider Access

920

921

### Providers Interface

922

923

Injectable interface for accessing provider instances.

924

925

```java { .api }

926

public interface Providers {

927

928

<T> MessageBodyReader<T> getMessageBodyReader(Class<T> type, Type genericType,

929

Annotation[] annotations,

930

MediaType mediaType);

931

932

<T> MessageBodyWriter<T> getMessageBodyWriter(Class<T> type, Type genericType,

933

Annotation[] annotations,

934

MediaType mediaType);

935

936

<T extends Throwable> ExceptionMapper<T> getExceptionMapper(Class<T> type);

937

938

<T> ContextResolver<T> getContextResolver(Class<T> contextType,

939

MediaType mediaType);

940

}

941

```

942

943

## Runtime Delegate

944

945

### RuntimeDelegate Class

946

947

Central class for JAX-RS runtime integration.

948

949

```java { .api }

950

public abstract class RuntimeDelegate {

951

952

public static RuntimeDelegate getInstance();

953

public static void setInstance(RuntimeDelegate rd);

954

955

public abstract UriBuilder createUriBuilder();

956

public abstract Response.ResponseBuilder createResponseBuilder();

957

public abstract Variant.VariantListBuilder createVariantListBuilder();

958

public abstract <T> T createEndpoint(Application application, Class<T> endpointType)

959

throws IllegalArgumentException, UnsupportedOperationException;

960

961

public abstract <T> HeaderDelegate<T> createHeaderDelegate(Class<T> type);

962

963

public static abstract class HeaderDelegate<T> {

964

public abstract T fromString(String value);

965

public abstract String toString(T value);

966

}

967

}

968

```

969

970

**Provider Usage Examples:**

971

972

```java

973

@Path("/provider-usage")

974

public class ProviderUsageExample {

975

976

@Context

977

private Providers providers;

978

979

@POST

980

@Path("/transform")

981

public Response transformData(@Context HttpHeaders headers,

982

InputStream inputStream) throws IOException {

983

984

MediaType inputType = headers.getMediaType();

985

986

// Get appropriate reader

987

MessageBodyReader<Object> reader = providers.getMessageBodyReader(

988

Object.class, Object.class, new Annotation[0], inputType);

989

990

if (reader == null) {

991

return Response.status(Response.Status.UNSUPPORTED_MEDIA_TYPE).build();

992

}

993

994

// Read input

995

Object data = reader.readFrom(Object.class, Object.class, new Annotation[0],

996

inputType, headers.getRequestHeaders(), inputStream);

997

998

// Transform data

999

Object transformed = transformationService.transform(data);

1000

1001

// Get appropriate writer for JSON output

1002

MessageBodyWriter<Object> writer = providers.getMessageBodyWriter(

1003

Object.class, Object.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

1004

1005

if (writer == null) {

1006

return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();

1007

}

1008

1009

return Response.ok(transformed, MediaType.APPLICATION_JSON).build();

1010

}

1011

}

1012

```