Jakarta REST (JAX-RS) is the standard Java API for building RESTful web services. Implementations include Jersey (reference), RESTEasy, and Apache CXF.

Setup (Jersey)

  <dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>3.1.5</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>3.1.5</version>
</dependency>
  

Resource Class

  @Path("/users")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class UserResource {
    private final UserService userService;

    public UserResource(UserService userService) {
        this.userService = userService;
    }

    @GET
    public List<UserDto> getAllUsers(
            @QueryParam("page") @DefaultValue("0") int page,
            @QueryParam("size") @DefaultValue("20") int size) {
        return userService.findAll(page, size);
    }

    @GET
    @Path("/{id}")
    public Response getUser(@PathParam("id") Long id) {
        return userService.findById(id)
            .map(user -> Response.ok(user).build())
            .orElse(Response.status(Response.Status.NOT_FOUND).build());
    }

    @POST
    public Response createUser(@Valid CreateUserRequest request, @Context UriInfo uriInfo) {
        UserDto created = userService.create(request);
        URI location = uriInfo.getAbsolutePathBuilder().path(created.getId().toString()).build();
        return Response.created(location).entity(created).build();
    }

    @PUT
    @Path("/{id}")
    public UserDto updateUser(@PathParam("id") Long id, @Valid UpdateUserRequest request) {
        return userService.update(id, request);
    }

    @DELETE
    @Path("/{id}")
    public Response deleteUser(@PathParam("id") Long id) {
        userService.delete(id);
        return Response.noContent().build();
    }
}
  

Key Annotations

Annotation Purpose
@Path Resource URI path
@GET/@POST/@PUT/@DELETE HTTP method
@PathParam URI template parameter
@QueryParam Query string parameter
@HeaderParam HTTP header value
@CookieParam Cookie value
@Produces Response content type
@Consumes Request content type
@Context Inject runtime context (UriInfo, HttpHeaders)

Exception Handling

  @Provider
public class NotFoundExceptionMapper implements ExceptionMapper<NotFoundException> {
    @Override
    public Response toResponse(NotFoundException ex) {
        return Response.status(Response.Status.NOT_FOUND)
            .entity(Map.of("error", ex.getMessage()))
            .type(MediaType.APPLICATION_JSON)
            .build();
    }
}
  

Sub-Resources

  @Path("/users/{userId}/orders")
public class UserOrderResource {
    @GET
    public List<OrderDto> getOrders(@PathParam("userId") Long userId) {
        return orderService.findByUserId(userId);
    }

    @POST
    public Response createOrder(@PathParam("userId") Long userId, CreateOrderRequest request) {
        OrderDto order = orderService.create(userId, request);
        return Response.status(Response.Status.CREATED).entity(order).build();
    }
}
  

Filters

  @Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthFilter implements ContainerRequestFilter {
    @Override
    public void filter(ContainerRequestContext ctx) throws IOException {
        String auth = ctx.getHeaderString("Authorization");
        if (auth == null || !auth.startsWith("Bearer ")) {
            ctx.abortWith(Response.status(Response.Status.UNAUTHORIZED)
                .entity("{\"error\": \"Missing token\"}").build());
        }
    }
}
  

JAX-RS vs Spring MVC

Feature JAX-RS Spring MVC
Standard Jakarta EE standard Spring framework
Annotations @Path, @GET @RequestMapping, @GetMapping
DI CDI / HK2 Spring DI
Ecosystem Java EE/Jakarta EE Spring Boot
Best for Jakarta EE apps Spring Boot apps

Best Practices

  • Use @Valid with Bean Validation for input validation
  • Return Response objects for full control over status and headers
  • Register exception mappers for consistent error responses
  • Use sub-resource locators for nested resources
  • For Spring Boot projects, prefer Spring MVC/WebFlux over JAX-RS