or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/maven-com-netflix-feign--feign-jaxrs

JAX-RS annotation integration module for Netflix's Feign HTTP client library

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/com.netflix.feign/feign-jaxrs@7.6.x

To install, run

npx @tessl/cli install tessl/maven-com-netflix-feign--feign-jaxrs@7.6.0

index.mddocs/

Feign JAX-RS

Feign JAX-RS is a module that enables the use of standard JAX-RS annotations (like @GET, @POST, @Path, @PathParam) with Netflix's Feign HTTP client library instead of Feign's native annotations. This allows developers familiar with JAX-RS to leverage Feign's declarative HTTP client capabilities while maintaining consistency with existing JAX-RS-based code.

Package Information

  • Package Name: feign-jaxrs
  • Package Type: Maven (Java)
  • Group ID: com.netflix.feign
  • Artifact ID: feign-jaxrs
  • Language: Java
  • Installation: Add to Maven dependencies:
<dependency>
    <groupId>com.netflix.feign</groupId>
    <artifactId>feign-jaxrs</artifactId>
    <version>7.6.0</version>
</dependency>

Or Gradle:

compile 'com.netflix.feign:feign-jaxrs:7.6.0'

Core Imports

import feign.jaxrs.JAXRSModule;
import feign.Contract;

Basic Usage

import feign.Feign;
import feign.jaxrs.JAXRSModule;
import javax.ws.rs.*;
import java.util.List;

// Define your API interface using JAX-RS annotations
@Path("/repos")
interface GitHubAPI {
    @GET
    @Path("/{owner}/{repo}/contributors")
    List<Contributor> getContributors(@PathParam("owner") String owner,
                                     @PathParam("repo") String repo);
}

// Configure Feign with JAX-RS module
@Module(includes = JAXRSModule.class)
class MyModule {
    // Additional configuration
}

// Create client instance
GitHubAPI github = Feign.create(GitHubAPI.class, "https://api.github.com", new MyModule());

// Use the client
List<Contributor> contributors = github.getContributors("netflix", "feign");

Architecture

The feign-jaxrs module consists of two main components:

  1. JAXRSModule: A Dagger module that provides the JAX-RS contract implementation
  2. JAXRSContract: The core implementation that processes JAX-RS annotations into Feign request templates

The module acts as a bridge between JAX-RS annotation semantics and Feign's internal request building mechanism, translating standard JAX-RS annotations into Feign's MethodMetadata format.

Capabilities

Dagger Module Configuration

The JAXRSModule class provides dependency injection configuration for integrating JAX-RS annotation processing with Feign.

@dagger.Module(library = true, overrides = true)
public final class JAXRSModule {
    @Provides
    Contract provideContract();
}

Module constants:

static final String ACCEPT = "Accept";
static final String CONTENT_TYPE = "Content-Type";

JAX-RS Contract Implementation

The JAXRSContract processes JAX-RS annotations and converts them into Feign request metadata.

public static final class JAXRSContract extends Contract.BaseContract {
    @Override
    public MethodMetadata parseAndValidatateMetadata(Method method);
    
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, 
                                           Annotation methodAnnotation, 
                                           Method method);
    
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, 
                                                   Annotation[] annotations, 
                                                   int paramIndex);
}

Core contract methods:

  • parseAndValidatateMetadata(): Parses class-level @Path annotations and builds method metadata
  • processAnnotationOnMethod(): Handles method-level annotations (@GET, @POST, @Path, @Produces, @Consumes)
  • processAnnotationsOnParameter(): Processes parameter annotations (@PathParam, @QueryParam, @HeaderParam, @FormParam)

Supported JAX-RS Annotations

Type-Level Annotations

@Path: Defines the base path for all methods in the interface.

@Path("/api/v1/users")
interface UserAPI {
    // All methods inherit /api/v1/users as base path
}
  • Appends value to Target.url()
  • Can contain path parameter tokens
  • Must not be empty or null
  • Leading slash is added automatically if missing

Method-Level Annotations

HTTP Method Annotations: Define the HTTP method for requests.

@GET     // HTTP GET method
@POST    // HTTP POST method  
@PUT     // HTTP PUT method
@DELETE  // HTTP DELETE method

@Path: Defines method-specific path segments.

@GET
@Path("/profile")  // Appends to base path
User getProfile();
  • Appends to class-level @Path
  • Can contain path parameter tokens
  • Leading slash added automatically when needed
  • Must not be empty or null

@Produces: Sets the Accept header for content negotiation.

@GET
@Produces("application/json")  // Sets Accept: application/json
User getUser();
  • Uses first value in array as Accept header
  • Must not be empty or null
  • Only first value is used if multiple provided

@Consumes: Sets the Content-Type header for request body.

@POST
@Consumes("application/json")  // Sets Content-Type: application/json
void createUser(User user);
  • Uses first value in array as Content-Type header
  • Must not be empty or null
  • Only first value is used if multiple provided

Parameter-Level Annotations

@PathParam: Links method parameters to path template variables.

@GET
@Path("/users/{userId}")
User getUser(@PathParam("userId") String userId);
  • Parameter name must not be empty or null
  • Links parameter value to path template variable
  • Used for URL path parameter substitution

@QueryParam: Links parameters to HTTP query parameters.

@GET
User searchUsers(@QueryParam("name") String name,
                @QueryParam("limit") Integer limit);
  • Parameter name must not be empty or null
  • Null parameter values are omitted from query string
  • Multiple parameters create multiple query parameters

@HeaderParam: Links parameters to custom HTTP headers.

@GET
User getUser(@HeaderParam("Authorization") String authToken,
            @HeaderParam("X-Request-ID") String requestId);
  • Parameter name must not be empty or null
  • Used for custom HTTP headers
  • Header name used exactly as specified

@FormParam: Links parameters to form data fields.

@POST
@Consumes("application/x-www-form-urlencoded")
void login(@FormParam("username") String username,
          @FormParam("password") String password);
  • Parameter name must not be empty or null
  • Used with form-encoded request bodies
  • Processed by Feign's form encoder

Error Handling

The JAX-RS contract throws IllegalStateException in the following cases:

  • Empty or null annotation values: When @Path, @PathParam, @QueryParam, @HeaderParam, @FormParam, @Produces, or @Consumes have empty or null values
  • Multiple HTTP methods: When a single method has multiple HTTP method annotations
  • Invalid annotation combinations: When annotations are used incorrectly
// These will throw IllegalStateException:
@Path("")                                    // Empty path
@PathParam("") String param                  // Empty path param name
@QueryParam(null) String query               // Null query param name
@Produces({}) Response get()                 // Empty produces array
@GET @POST void invalidMethod()              // Multiple HTTP methods

Limitations

  • JAX-RS 1.1 compatibility: Targets JAX-RS 1.1 specification, not 2.0+
  • Interface-only support: Only supports Java interfaces, not abstract or concrete classes
  • Best-effort implementation: Not 100% JAX-RS compliant, focuses on common client-side patterns
  • Single value support: @Produces and @Consumes only use the first value in arrays
  • No server-side features: Designed for client-side HTTP mapping only

Dependencies

  • javax.ws.rs:jsr311-api:1.1.1: JAX-RS 1.1 API specification
  • feign-core: Core Feign HTTP client library
  • dagger: Dependency injection framework

Types

// Main module class
@dagger.Module(library = true, overrides = true)
public final class JAXRSModule {
    static final String ACCEPT = "Accept";
    static final String CONTENT_TYPE = "Content-Type";
    
    @Provides
    Contract provideContract();
}

// Contract implementation
public static final class JAXRSContract extends Contract.BaseContract {
    @Override
    public MethodMetadata parseAndValidatateMetadata(Method method);
    
    @Override
    protected void processAnnotationOnMethod(MethodMetadata data, 
                                           Annotation methodAnnotation, 
                                           Method method);
    
    @Override
    protected boolean processAnnotationsOnParameter(MethodMetadata data, 
                                                   Annotation[] annotations, 
                                                   int paramIndex);
}

Usage Examples

Complete API Interface Example

import javax.ws.rs.*;
import java.util.List;

@Path("/api/v1")
@Produces("application/json")
public interface UserService {
    
    @GET
    @Path("/users")
    List<User> getAllUsers(@QueryParam("limit") Integer limit,
                          @QueryParam("offset") Integer offset);
    
    @GET  
    @Path("/users/{id}")
    User getUserById(@PathParam("id") String userId);
    
    @POST
    @Path("/users")
    @Consumes("application/json")
    User createUser(User user);
    
    @PUT
    @Path("/users/{id}")
    @Consumes("application/json") 
    User updateUser(@PathParam("id") String userId, User user);
    
    @DELETE
    @Path("/users/{id}")
    void deleteUser(@PathParam("id") String userId);
    
    @POST
    @Path("/auth/login")
    @Consumes("application/x-www-form-urlencoded")
    AuthToken login(@FormParam("username") String username,
                   @FormParam("password") String password);
    
    @GET
    @Path("/users/me")
    User getCurrentUser(@HeaderParam("Authorization") String bearerToken);
}

Dagger Module Configuration

import dagger.Module;
import dagger.Provides;
import feign.Logger;
import feign.jaxrs.JAXRSModule;

@Module(includes = {JAXRSModule.class, GsonModule.class})
public class ApiModule {
    
    @Provides
    Logger.Level provideLogLevel() {
        return Logger.Level.BASIC;
    }
    
    @Provides  
    Logger provideLogger() {
        return new Logger.ErrorLogger();
    }
}

Client Creation and Usage

import feign.Feign;

public class ApiClient {
    private final UserService userService;
    
    public ApiClient(String baseUrl) {
        this.userService = Feign.create(UserService.class, baseUrl, new ApiModule());
    }
    
    public void demonstrateUsage() {
        // Get all users with pagination
        List<User> users = userService.getAllUsers(10, 0);
        
        // Get specific user
        User user = userService.getUserById("123");
        
        // Create new user
        User newUser = new User("john", "john@example.com");
        User created = userService.createUser(newUser);
        
        // Update user
        created.setEmail("newemail@example.com");
        User updated = userService.updateUser(created.getId(), created);
        
        // Authenticate
        AuthToken token = userService.login("john", "password123");
        
        // Get current user with auth header
        User currentUser = userService.getCurrentUser("Bearer " + token.getAccessToken());
        
        // Delete user
        userService.deleteUser(created.getId());
    }
}