Feign JAX-RS module enables Feign HTTP clients to use standard JAX-RS 1.1 specification annotations instead of Feign's proprietary annotations. It provides annotation processing capabilities that translate JAX-RS annotations into Feign's internal request templates.
The main contract class that processes JAX-RS annotations and converts them to Feign request templates.
/**
* Contract implementation that processes JAX-RS annotations.
* Extends Contract.BaseContract to provide JAX-RS 1.1 annotation support.
*/
public final class JAXRSContract extends Contract.BaseContract {
/** Accept header constant */
static final String ACCEPT = "Accept";
/** Content-Type header constant */
static final String CONTENT_TYPE = "Content-Type";
/**
* Parses and validates method metadata from JAX-RS annotated methods.
* @param targetType The interface class containing the method
* @param method The method to parse
* @return MethodMetadata containing parsed request information
*/
protected MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method);
}Type-level annotations apply to the entire interface class.
/**
* @Path - Defines base path for all methods in the interface
* Applied to interface classes to set common URL prefix
*/
@Path("/api/v1")
interface MyAPI {
// methods inherit the base path
}
/**
* @Produces - Sets default Accept header for all methods
* First media type value is used as Accept header
*/
@Produces("application/json")
interface MyAPI {
// methods inherit the Accept header
}
/**
* @Consumes - Sets default Content-Type header for all methods
* First media type value is used as Content-Type header
*/
@Consumes("application/json")
interface MyAPI {
// methods inherit the Content-Type header
}Method-level annotations define HTTP method and additional request properties.
/**
* HTTP Method Annotations - Set the HTTP method for the request
* Supported: @GET, @POST, @PUT, @DELETE, @HEAD, @OPTIONS, @PATCH
*/
@GET
@POST
@PUT
@DELETE
// Any annotation with @HttpMethod meta-annotation
/**
* @Path - Appends path to the base URL, supports path parameters
* Can include path parameters with optional regex patterns
*/
@Path("/users/{id}")
@Path("/search/{query:.+}") // with regex
@Path("/items/{id:[0-9]+}") // numeric regex
/**
* @Produces - Sets Accept header for this method (overrides type-level)
* First media type value is used
*/
@Produces("application/xml")
/**
* @Consumes - Sets Content-Type header for this method (overrides type-level)
* First media type value is used
*/
@Consumes("application/xml")Parameter-level annotations bind method parameters to different parts of the HTTP request.
/**
* @PathParam - Links parameter value to path template variable
* Parameter name must match template variable name
*/
@PathParam("id") String userId
/**
* @QueryParam - Links parameter to query parameter
* Null values are skipped (query parameter not included)
*/
@QueryParam("filter") String filter
@QueryParam("limit") Integer limit // null skips parameter
/**
* @HeaderParam - Links parameter to HTTP header
* Parameter value becomes header value
*/
@HeaderParam("Authorization") String authToken
@HeaderParam("User-Agent") String userAgent
/**
* @FormParam - Links parameter to form data field
* Used with application/x-www-form-urlencoded content type
*/
@FormParam("username") String username
@FormParam("password") String passwordimport feign.Feign;
import feign.jaxrs.JAXRSContract;
import javax.ws.rs.*;
import java.util.List;
@Path("/api/v1")
@Produces("application/json")
interface UserAPI {
@GET
@Path("/users/{id}")
User getUser(@PathParam("id") String userId);
@GET
@Path("/users")
List<User> searchUsers(@QueryParam("name") String nameFilter,
@QueryParam("active") Boolean activeOnly);
@POST
@Path("/users")
@Consumes("application/json")
User createUser(User user);
}
// Create client with JAX-RS contract
UserAPI userAPI = Feign.builder()
.contract(new JAXRSContract())
.target(UserAPI.class, "https://api.example.com");interface ItemAPI {
@GET
@Path("/items/{id:[0-9]+}")
Item getItem(@PathParam("id") String id);
@GET
@Path("/search/{query:.+}")
List<Item> search(@PathParam("query") String searchQuery);
}interface AuthAPI {
@POST
@Path("/login")
@Consumes("application/x-www-form-urlencoded")
Token login(@FormParam("username") String username,
@FormParam("password") String password,
@FormParam("remember") Boolean remember);
}@Produces("application/json") // Default Accept header
interface APIClient {
@GET
@Path("/data")
@Produces("application/xml") // Override Accept header for this method
Data getDataAsXML();
@POST
@Path("/data")
@Consumes("application/json") // Content-Type for request body
void createData(Data data, @HeaderParam("X-Custom") String customHeader);
}Add the JAX-RS module dependency:
dependencies {
compile 'com.netflix.feign:feign-jaxrs:8.18.0'
compile 'javax.ws.rs:jsr311-api:1.1.1'
}@Produces/@Consumes arraysThe JAX-RS contract validates annotation values and throws IllegalStateException for invalid configurations:
@Path values@PathParam, @QueryParam, etc.)@Produces or @Consumes arrays