or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-io-quarkus--quarkus-rest-client-jackson-deployment

Quarkus deployment extension that provides build-time configuration and processing for integrating Jackson JSON serialization with the reactive REST client.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/io.quarkus/quarkus-rest-client-jackson-deployment@3.23.x

To install, run

npx @tessl/cli install tessl/maven-io-quarkus--quarkus-rest-client-jackson-deployment@3.23.0

index.mddocs/

Quarkus REST Client Jackson Deployment

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.

Package Information

  • Package Name: quarkus-rest-client-jackson-deployment
  • Package Type: maven
  • Language: Java
  • Installation: Include in your Maven project dependencies or add as a Quarkus extension
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-rest-client-jackson-deployment</artifactId>
    <version>3.23.0</version>
</dependency>

Add via Quarkus CLI:

quarkus extension add rest-client-reactive-jackson

Core Imports

For deployment extension usage (typically in build processors):

import io.quarkus.rest.client.reactive.jackson.deployment.RestClientReactiveJacksonProcessor;
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.deployment.annotations.BuildStep;

For runtime usage (in REST client interfaces):

import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.JacksonUtil;

For message body processing:

import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyReader;
import io.quarkus.rest.client.reactive.jackson.runtime.serialisers.ClientJacksonMessageBodyWriter;
import org.jboss.resteasy.reactive.client.spi.RestClientRequestContext;

Basic Usage

Using the Extension

The extension is automatically activated when added to your Quarkus project. No additional configuration is required for basic JSON processing.

import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.core.MediaType;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;

@RegisterRestClient(baseUri = "https://api.example.com")
public interface UserService {
    
    @GET
    @Path("/users/{id}")
    @Produces(MediaType.APPLICATION_JSON)
    User getUser(@PathParam("id") Long id);
    
    @POST
    @Path("/users")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    User createUser(CreateUserRequest request);
}

Custom Object Mapper Configuration

Define a custom ObjectMapper for specific REST client configurations:

import io.quarkus.rest.client.reactive.jackson.ClientObjectMapper;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.DeserializationFeature;

@RegisterRestClient(baseUri = "https://api.example.com")  
public interface UserService {

    @ClientObjectMapper
    static ObjectMapper objectMapper(ObjectMapper defaultObjectMapper) {
        return defaultObjectMapper.copy()
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
    }
    
    @GET
    @Path("/users/{id}")
    User getUser(@PathParam("id") Long id);
}

Architecture

The extension integrates with Quarkus' build-time optimization system and consists of several key components:

  • Build-time Processing: RestClientReactiveJacksonProcessor handles feature registration and bean configuration during build
  • Runtime Serialization: Jackson-based message body readers and writers handle JSON processing during runtime
  • CDI Integration: Automatic bean registration for dependency injection compatibility
  • Native Image Support: Proper configuration for GraalVM native compilation
  • Context Resolution: Support for per-client ObjectMapper configuration via JAX-RS context resolution

Capabilities

Build-time Feature Registration

Automatically registers the REST_CLIENT_JACKSON feature and configures required components.

public class RestClientReactiveJacksonProcessor {
    
    /**
     * Registers the REST_CLIENT_JACKSON feature
     */
    @BuildStep
    void feature(BuildProducer<FeatureBuildItem> features);
    
    /**
     * Configures Vert.x JSON reinitialization for native compilation
     */
    @BuildStep  
    ReinitializeVertxJsonBuildItem vertxJson();
    
    /**
     * Registers ClientObjectMapper annotation for client context resolution
     */
    @BuildStep
    void additionalProviders(BuildProducer<AnnotationToRegisterIntoClientContextBuildItem> annotation);
    
    /**
     * Registers Jackson message body readers and writers as CDI beans.
     * Only registers if Jackson provider is already defined in the application.
     */
    @BuildStep
    void additionalProviders(
        List<ResteasyReactiveJacksonProviderDefinedBuildItem> jacksonProviderDefined,
        BuildProducer<AdditionalBeanBuildItem> additionalBean,
        BuildProducer<MessageBodyReaderBuildItem> additionalReaders,
        BuildProducer<MessageBodyWriterBuildItem> additionalWriters);
    
    /**
     * Configures native image support by registering cleanup task service provider
     */
    @BuildStep
    void nativeSupport(BuildProducer<ServiceProviderBuildItem> serviceProviderProducer);
}

Custom Object Mapper Configuration

Annotation for defining per-client ObjectMapper instances with custom configuration.

/**
 * Annotation for defining custom ObjectMapper for specific REST client.
 * Must be placed on static methods in REST Client interfaces.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ClientObjectMapper {
}

Usage Requirements:

  • Must be placed on static methods in REST Client interfaces
  • Method can optionally accept default ObjectMapper as parameter
  • Should return ObjectMapper instance with desired configuration
  • Use copy() method on default mapper to inherit base settings

Usage Examples:

Simple custom mapper:

@ClientObjectMapper
static ObjectMapper objectMapper() {
    return new ObjectMapper()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
}

Inheriting from default mapper:

@ClientObjectMapper  
static ObjectMapper objectMapper(ObjectMapper defaultObjectMapper) {
    return defaultObjectMapper.copy()
        .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
        .configure(JsonParser.Feature.ALLOW_COMMENTS, true);
}

ObjectMapper Context Resolution

Utility for resolving ObjectMapper instances from JAX-RS context, enabling per-client customization.

/**
 * Utility class for resolving ObjectMapper from REST client context
 */
final class JacksonUtil {
    
    /**
     * Resolves ObjectMapper from REST client context, falling back to default if not found.
     * Supports per-client ObjectMapper customization via @ClientObjectMapper annotation.
     * 
     * @param responseMediaType the media type of the response
     * @param context the REST client request context containing configuration
     * @return ObjectMapper instance (custom or default)
     */
    static ObjectMapper getObjectMapperFromContext(MediaType responseMediaType, RestClientRequestContext context);
}

JSON Message Processing

Runtime components that handle JSON serialization and deserialization for REST client communication.

/**
 * Jackson-based message body reader for client-side JSON deserialization
 */
public class ClientJacksonMessageBodyReader extends AbstractJsonMessageBodyReader 
    implements ClientMessageBodyReader<Object> {
    
    private final ObjectMapper mapper;
    
    /**
     * Constructor with ObjectMapper dependency injection.
     * The injected mapper serves as default but can be overridden per-client.
     * 
     * @param mapper default ObjectMapper instance injected by CDI
     */
    @Inject
    public ClientJacksonMessageBodyReader(ObjectMapper mapper);
    
    /**
     * Standard JAX-RS reader method for JSON deserialization.
     * Uses default ObjectMapper without context resolution.
     */
    @Override
    public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations, 
                          MediaType mediaType, MultivaluedMap<String, String> httpHeaders, 
                          InputStream entityStream) throws IOException, WebApplicationException;
    
    /**
     * Client-specific reader method with REST client context support.
     * Resolves ObjectMapper from context using JacksonUtil, enabling per-client customization.
     */
    @Override
    public Object readFrom(Class<Object> type, Type genericType, Annotation[] annotations,
                          MediaType mediaType, MultivaluedMap<String, String> httpHeaders,
                          InputStream entityStream, RestClientRequestContext context) 
                          throws IOException, WebApplicationException;
}

/**
 * Jackson-based message body writer for client-side JSON serialization  
 */
public class ClientJacksonMessageBodyWriter implements ClientMessageBodyWriter<Object> {
    
    private final ObjectMapper mapper;
    
    /**
     * Constructor with ObjectMapper dependency injection.
     * The injected mapper serves as default but can be overridden per-client.
     * 
     * @param mapper default ObjectMapper instance injected by CDI
     */
    @Inject
    public ClientJacksonMessageBodyWriter(ObjectMapper mapper);
    
    /**
     * Indicates if type is writable for JSON serialization.
     * Always returns true for JSON media types.
     * 
     * @return true if the type can be serialized to JSON
     */
    @Override
    public boolean isWriteable(Class type, Type genericType, Annotation[] annotations, 
                              MediaType mediaType);
    
    /**
     * Standard JAX-RS writer method for JSON serialization.
     * Uses default ObjectMapper without context resolution.
     */
    @Override
    public void writeTo(Object o, Class<?> type, Type genericType, Annotation[] annotations,
                       MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
                       OutputStream entityStream) throws IOException, WebApplicationException;
    
    /**
     * Client-specific writer method with REST client context support.
     * Resolves ObjectMapper from context using JacksonUtil, enabling per-client customization.
     */
    @Override
    public void writeTo(Object o, Class<?> type, Type genericType, Annotation[] annotations,
                       MediaType mediaType, MultivaluedMap<String, Object> httpHeaders,
                       OutputStream entityStream, RestClientRequestContext context) 
                       throws IOException, WebApplicationException;
}

Resource Cleanup

Automatic cleanup of ObjectMapper caches when REST clients are closed.

/**
 * Cleanup task for ClientObjectMapper mappings when REST client is closed
 */
public class JacksonCleanupRestClientClosingTask implements RestClientClosingTask {
    
    /**
     * Cleans up cached ObjectMapper mappings for the closing client
     */
    @Override
    public void close(Context context);
}

Supported Media Types

JSON Deserialization (Reading)

  • application/json - Standard JSON format
  • application/x-ndjson - Newline delimited JSON
  • application/stream+json - JSON streaming format

JSON Serialization (Writing)

  • application/json - Standard JSON format

Error Handling

The extension handles JSON processing errors gracefully:

  • JsonParseException: Invalid JSON from server responses are caught and wrapped in ClientWebApplicationException with HTTP 200 status
  • Context Resolution: Failed ObjectMapper context resolution falls back to default mapper
  • Resource Cleanup: Automatic cleanup prevents memory leaks when clients are closed

Configuration

The extension uses the standard Quarkus configuration prefix quarkus.rest-client-reactive. for any REST client related settings.

Dependencies

Required Dependencies

  • io.quarkus:quarkus-rest-jackson-common-deployment - Common Jackson deployment utilities
  • io.quarkus:quarkus-rest-client-deployment - REST client deployment foundation
  • io.quarkus:quarkus-rest-client-jackson - Runtime components

Framework Integration

  • Jackson: com.fasterxml.jackson.databind.ObjectMapper for JSON processing
  • JAX-RS: Standard jakarta.ws.rs APIs for HTTP handling
  • RESTEasy Reactive: org.jboss.resteasy.reactive framework integration
  • Vert.x: io.vertx.core.json for JsonObject and JsonArray support
  • Quarkus CDI: jakarta.inject for dependency injection

Types

/**
 * Key class for caching ObjectMapper resolvers per REST client configuration
 */
public final class ResolverMapKey {
    
    /**
     * Creates a new resolver map key
     */
    public ResolverMapKey(Configuration configuration, Class<?> restClientClass);
    
    /**
     * Gets the JAX-RS configuration  
     */
    public Configuration getConfiguration();
    
    /**
     * Gets the REST client class
     */
    public Class<?> getRestClientClass();
    
    @Override
    public boolean equals(Object o);
    
    @Override  
    public int hashCode();
}

/**
 * Build item indicating that Vert.x JSON needs reinitialization for native compilation
 */
public final class ReinitializeVertxJsonBuildItem extends SimpleBuildItem {
}

/**
 * Build item for registering annotations that should be available in client context
 */
public final class AnnotationToRegisterIntoClientContextBuildItem extends MultiBuildItem {
    public AnnotationToRegisterIntoClientContextBuildItem(DotName annotation);
    public DotName getAnnotation();
}

/**
 * Marker build item indicating Jackson provider has been defined for RESTEasy Reactive
 */
public final class ResteasyReactiveJacksonProviderDefinedBuildItem extends SimpleBuildItem {
}