CtrlK
BlogDocsLog inGet started
Tessl Logo

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

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

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

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());
    }
}
Workspace
tessl
Visibility
Public
Created
Last updated
Describes
mavenpkg:maven/com.netflix.feign/feign-jaxrs@7.6.x
Publish Source
CLI
Badge
tessl/maven-com-netflix-feign--feign-jaxrs badge