Quarkus deployment extension that provides build-time configuration and processing for integrating Jackson JSON serialization with the reactive REST client.
npx @tessl/cli install tessl/maven-io-quarkus--quarkus-rest-client-jackson-deployment@3.23.00
# Quarkus REST Client Jackson Deployment
1
2
A Quarkus deployment extension that provides build-time configuration and processing for integrating Jackson JSON serialization/deserialization with the reactive REST client. This extension handles the automatic registration of Jackson message body readers and writers for JSON processing in REST client implementations, enabling seamless JSON data binding for client-side REST communication in Quarkus applications.
3
4
## Package Information
5
6
- **Package Name**: quarkus-rest-client-jackson-deployment
7
- **Package Type**: maven
8
- **Language**: Java
9
- **Installation**: Include in your Maven project dependencies or add as a Quarkus extension
10
11
```xml
12
<dependency>
13
<groupId>io.quarkus</groupId>
14
<artifactId>quarkus-rest-client-jackson-deployment</artifactId>
15
<version>3.23.0</version>
16
</dependency>
17
```
18
19
Add via Quarkus CLI:
20
```bash
21
quarkus extension add rest-client-reactive-jackson
22
```
23
24
## Core Imports
25
26
For deployment extension usage (typically in build processors):
27
28
```java
29
import io.quarkus.rest.client.reactive.jackson.deployment.RestClientReactiveJacksonProcessor;
30
import io.quarkus.deployment.builditem.FeatureBuildItem;
31
import io.quarkus.deployment.annotations.BuildStep;
32
```
33
34
For runtime usage (in REST client interfaces):
35
36
```java
37
import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
38
import com.fasterxml.jackson.databind.ObjectMapper;
39
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.JacksonUtil;
40
```
41
42
For message body processing:
43
44
```java
45
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyReader;
46
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter;
47
import org.jboss.resteasy.reactive.client.spi.RestClientRequestContext;
48
```
49
50
## Basic Usage
51
52
### Using the Extension
53
54
The extension is automatically activated when added to your Quarkus project. No additional configuration is required for basic JSON processing.
55
56
```java
57
import jakarta.ws.rs.GET;
58
import jakarta.ws.rs.POST;
59
import jakarta.ws.rs.Path;
60
import jakarta.ws.rs.PathParam;
61
import jakarta.ws.rs.Produces;
62
import jakarta.ws.rs.Consumes;
63
import jakarta.ws.rs.core.MediaType;
64
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
65
66
@RegisterRestClient(baseUri = "https://api.example.com")
67
public interface UserService {
68
69
@GET
70
@Path("/users/{id}")
71
@Produces(MediaType.APPLICATION_JSON)
72
User getUser(@PathParam("id") Long id);
73
74
@POST
75
@Path("/users")
76
@Consumes(MediaType.APPLICATION_JSON)
77
@Produces(MediaType.APPLICATION_JSON)
78
User createUser(CreateUserRequest request);
79
}
80
```
81
82
### Custom Object Mapper Configuration
83
84
Define a custom ObjectMapper for specific REST client configurations:
85
86
```java
87
import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
88
import com.fasterxml.jackson.databind.ObjectMapper;
89
import com.fasterxml.jackson.databind.DeserializationFeature;
90
91
@RegisterRestClient(baseUri = "https://api.example.com")
92
public interface UserService {
93
94
@ClientObjectMapper
95
static ObjectMapper objectMapper(ObjectMapper defaultObjectMapper) {
96
return defaultObjectMapper.copy()
97
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
98
.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
99
}
100
101
@GET
102
@Path("/users/{id}")
103
User getUser(@PathParam("id") Long id);
104
}
105
```
106
107
## Architecture
108
109
The extension integrates with Quarkus' build-time optimization system and consists of several key components:
110
111
- **Build-time Processing**: `RestClientReactiveJacksonProcessor` handles feature registration and bean configuration during build
112
- **Runtime Serialization**: Jackson-based message body readers and writers handle JSON processing during runtime
113
- **CDI Integration**: Automatic bean registration for dependency injection compatibility
114
- **Native Image Support**: Proper configuration for GraalVM native compilation
115
- **Context Resolution**: Support for per-client ObjectMapper configuration via JAX-RS context resolution
116
117
## Capabilities
118
119
### Build-time Feature Registration
120
121
Automatically registers the REST_CLIENT_JACKSON feature and configures required components.
122
123
```java { .api }
124
public class RestClientReactiveJacksonProcessor {
125
126
/**
127
* Registers the REST_CLIENT_JACKSON feature
128
*/
129
@BuildStep
130
void feature(BuildProducer<FeatureBuildItem> features);
131
132
/**
133
* Configures Vert.x JSON reinitialization for native compilation
134
*/
135
@BuildStep
136
ReinitializeVertxJsonBuildItem vertxJson();
137
138
/**
139
* Registers ClientObjectMapper annotation for client context resolution
140
*/
141
@BuildStep
142
void additionalProviders(BuildProducer<AnnotationToRegisterIntoClientContextBuildItem> annotation);
143
144
/**
145
* Registers Jackson message body readers and writers as CDI beans.
146
* Only registers if Jackson provider is already defined in the application.
147
*/
148
@BuildStep
149
void additionalProviders(
150
List<ResteasyReactiveJacksonProviderDefinedBuildItem> jacksonProviderDefined,
151
BuildProducer<AdditionalBeanBuildItem> additionalBean,
152
BuildProducer<MessageBodyReaderBuildItem> additionalReaders,
153
BuildProducer<MessageBodyWriterBuildItem> additionalWriters);
154
155
/**
156
* Configures native image support by registering cleanup task service provider
157
*/
158
@BuildStep
159
void nativeSupport(BuildProducer<ServiceProviderBuildItem> serviceProviderProducer);
160
}
161
```
162
163
### Custom Object Mapper Configuration
164
165
Annotation for defining per-client ObjectMapper instances with custom configuration.
166
167
```java { .api }
168
/**
169
* Annotation for defining custom ObjectMapper for specific REST client.
170
* Must be placed on static methods in REST Client interfaces.
171
*/
172
@Retention(RetentionPolicy.RUNTIME)
173
@Target(ElementType.METHOD)
174
public @interface ClientObjectMapper {
175
}
176
```
177
178
**Usage Requirements:**
179
- Must be placed on static methods in REST Client interfaces
180
- Method can optionally accept default ObjectMapper as parameter
181
- Should return ObjectMapper instance with desired configuration
182
- Use `copy()` method on default mapper to inherit base settings
183
184
**Usage Examples:**
185
186
Simple custom mapper:
187
```java
188
@ClientObjectMapper
189
static ObjectMapper objectMapper() {
190
return new ObjectMapper()
191
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
192
}
193
```
194
195
Inheriting from default mapper:
196
```java
197
@ClientObjectMapper
198
static ObjectMapper objectMapper(ObjectMapper defaultObjectMapper) {
199
return defaultObjectMapper.copy()
200
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
201
.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
202
}
203
```
204
205
### ObjectMapper Context Resolution
206
207
Utility for resolving ObjectMapper instances from JAX-RS context, enabling per-client customization.
208
209
```java { .api }
210
/**
211
* Utility class for resolving ObjectMapper from REST client context
212
*/
213
final class JacksonUtil {
214
215
/**
216
* Resolves ObjectMapper from REST client context, falling back to default if not found.
217
* Supports per-client ObjectMapper customization via @ClientObjectMapper annotation.
218
*
219
* @param responseMediaType the media type of the response
220
* @param context the REST client request context containing configuration
221
* @return ObjectMapper instance (custom or default)
222
*/
223
static ObjectMapper getObjectMapperFromContext(MediaType responseMediaType, RestClientRequestContext context);
224
}
225
```
226
227
### JSON Message Processing
228
229
Runtime components that handle JSON serialization and deserialization for REST client communication.
230
231
```java { .api }
232
/**
233
* Jackson-based message body reader for client-side JSON deserialization
234
*/
235
public class ClientJacksonMessageBodyReader extends AbstractJsonMessageBodyReader
236
implements ClientMessageBodyReader<Object> {
237
238
private final ObjectMapper mapper;
239
240
/**
241
* Constructor with ObjectMapper dependency injection.
242
* The injected mapper serves as default but can be overridden per-client.
243
*
244
* @param mapper default ObjectMapper instance injected by CDI
245
*/
246
@Inject
247
public ClientJacksonMessageBodyReader(ObjectMapper mapper);
248
249
/**
250
* Standard JAX-RS reader method for JSON deserialization.
251
* Uses default ObjectMapper without context resolution.
252
*/
253
@Override
254
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations,
255
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
256
InputStream entityStream) throws IOException, WebApplicationException;
257
258
/**
259
* Client-specific reader method with REST client context support.
260
* Resolves ObjectMapper from context using JacksonUtil, enabling per-client customization.
261
*/
262
@Override
263
public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations,
264
MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
265
InputStream entityStream, RestClientRequestContext context)
266
throws IOException, WebApplicationException;
267
}
268
269
/**
270
* Jackson-based message body writer for client-side JSON serialization
271
*/
272
public class ClientJacksonMessageBodyWriter implements ClientMessageBodyWriter<Object> {
273
274
private final ObjectMapper mapper;
275
276
/**
277
* Constructor with ObjectMapper dependency injection.
278
* The injected mapper serves as default but can be overridden per-client.
279
*
280
* @param mapper default ObjectMapper instance injected by CDI
281
*/
282
@Inject
283
public ClientJacksonMessageBodyWriter(ObjectMapper mapper);
284
285
/**
286
* Indicates if type is writable for JSON serialization.
287
* Always returns true for JSON media types.
288
*
289
* @return true if the type can be serialized to JSON
290
*/
291
@Override
292
public boolean isWriteable(Class type, Type genericType, Annotation[] annotations,
293
MediaType mediaType);
294
295
/**
296
* Standard JAX-RS writer method for JSON serialization.
297
* Uses default ObjectMapper without context resolution.
298
*/
299
@Override
300
public void writeTo(Object o, Class<?> type, Type genericType, Annotation[] annotations,
301
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
302
OutputStream entityStream) throws IOException, WebApplicationException;
303
304
/**
305
* Client-specific writer method with REST client context support.
306
* Resolves ObjectMapper from context using JacksonUtil, enabling per-client customization.
307
*/
308
@Override
309
public void writeTo(Object o, Class<?> type, Type genericType, Annotation[] annotations,
310
MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
311
OutputStream entityStream, RestClientRequestContext context)
312
throws IOException, WebApplicationException;
313
}
314
```
315
316
### Resource Cleanup
317
318
Automatic cleanup of ObjectMapper caches when REST clients are closed.
319
320
```java { .api }
321
/**
322
* Cleanup task for ClientObjectMapper mappings when REST client is closed
323
*/
324
public class JacksonCleanupRestClientClosingTask implements RestClientClosingTask {
325
326
/**
327
* Cleans up cached ObjectMapper mappings for the closing client
328
*/
329
@Override
330
public void close(Context context);
331
}
332
```
333
334
## Supported Media Types
335
336
### JSON Deserialization (Reading)
337
- `application/json` - Standard JSON format
338
- `application/x-ndjson` - Newline delimited JSON
339
- `application/stream+json` - JSON streaming format
340
341
### JSON Serialization (Writing)
342
- `application/json` - Standard JSON format
343
344
## Error Handling
345
346
The extension handles JSON processing errors gracefully:
347
348
- **JsonParseException**: Invalid JSON from server responses are caught and wrapped in `ClientWebApplicationException` with HTTP 200 status
349
- **Context Resolution**: Failed ObjectMapper context resolution falls back to default mapper
350
- **Resource Cleanup**: Automatic cleanup prevents memory leaks when clients are closed
351
352
## Configuration
353
354
The extension uses the standard Quarkus configuration prefix `quarkus.rest-client-reactive.` for any REST client related settings.
355
356
## Dependencies
357
358
### Required Dependencies
359
- `io.quarkus:quarkus-rest-jackson-common-deployment` - Common Jackson deployment utilities
360
- `io.quarkus:quarkus-rest-client-deployment` - REST client deployment foundation
361
- `io.quarkus:quarkus-rest-client-jackson` - Runtime components
362
363
### Framework Integration
364
- **Jackson**: `com.fasterxml.jackson.databind.ObjectMapper` for JSON processing
365
- **JAX-RS**: Standard `jakarta.ws.rs` APIs for HTTP handling
366
- **RESTEasy Reactive**: `org.jboss.resteasy.reactive` framework integration
367
- **Vert.x**: `io.vertx.core.json` for JsonObject and JsonArray support
368
- **Quarkus CDI**: `jakarta.inject` for dependency injection
369
370
## Types
371
372
```java { .api }
373
/**
374
* Key class for caching ObjectMapper resolvers per REST client configuration
375
*/
376
public final class ResolverMapKey {
377
378
/**
379
* Creates a new resolver map key
380
*/
381
public ResolverMapKey(Configuration configuration, Class<?> restClientClass);
382
383
/**
384
* Gets the JAX-RS configuration
385
*/
386
public Configuration getConfiguration();
387
388
/**
389
* Gets the REST client class
390
*/
391
public Class<?> getRestClientClass();
392
393
@Override
394
public boolean equals(Object o);
395
396
@Override
397
public int hashCode();
398
}
399
400
/**
401
* Build item indicating that Vert.x JSON needs reinitialization for native compilation
402
*/
403
public final class ReinitializeVertxJsonBuildItem extends SimpleBuildItem {
404
}
405
406
/**
407
* Build item for registering annotations that should be available in client context
408
*/
409
public final class AnnotationToRegisterIntoClientContextBuildItem extends MultiBuildItem {
410
public AnnotationToRegisterIntoClientContextBuildItem(DotName annotation);
411
public DotName getAnnotation();
412
}
413
414
/**
415
* Marker build item indicating Jackson provider has been defined for RESTEasy Reactive
416
*/
417
public final class ResteasyReactiveJacksonProviderDefinedBuildItem extends SimpleBuildItem {
418
}
419
```