CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-javax-ws-rs--javax-ws-rs-api

Java API for RESTful Web Services

Pending
Overview
Eval results
Files

server-container.mddocs/

Server Container

The server container APIs provide server-side processing capabilities including request/response filtering, asynchronous processing, resource management, and dynamic configuration. These APIs enable cross-cutting concerns like authentication, logging, caching, and custom request processing.

Core Imports

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerResponseContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseFilter;
import javax.ws.rs.container.DynamicFeature;
import javax.ws.rs.core.FeatureContext;
import javax.ws.rs.container.PreMatching;
import javax.ws.rs.container.Suspended;

import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.container.CompletionCallback;
import javax.ws.rs.container.ConnectionCallback;
import javax.ws.rs.container.TimeoutHandler;

import javax.ws.rs.container.ResourceContext;
import javax.ws.rs.container.ResourceInfo;

import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

Request and Response Context

ContainerRequestContext Interface

Provides access to request processing information on the server side.

public interface ContainerRequestContext {
    
    Object getProperty(String name);
    Collection<String> getPropertyNames();
    void setProperty(String name, Object object);
    void removeProperty(String name);
    
    UriInfo getUriInfo();
    void setRequestUri(URI requestUri);
    void setRequestUri(URI baseUri, URI requestUri);
    
    Request getRequest();
    String getMethod();
    void setMethod(String method);
    
    MultivaluedMap<String, String> getHeaders();
    String getHeaderString(String name);
    
    Date getDate();
    Locale getLanguage();
    int getLength();
    MediaType getMediaType();
    List<MediaType> getAcceptableMediaTypes();
    List<Locale> getAcceptableLanguages();
    
    Map<String, Cookie> getCookies();
    
    boolean hasEntity();
    InputStream getEntityStream();
    void setEntityStream(InputStream input);
    
    SecurityContext getSecurityContext();
    void setSecurityContext(SecurityContext context);
    
    void abortWith(Response response);
}

ContainerResponseContext Interface

Provides access to response processing information on the server side.

public interface ContainerResponseContext {
    
    int getStatus();
    void setStatus(int code);
    StatusType getStatusInfo();
    void setStatusInfo(StatusType statusInfo);
    
    MultivaluedMap<String, Object> getHeaders();
    MultivaluedMap<String, String> getStringHeaders();
    String getHeaderString(String name);
    
    Set<String> getAllowedMethods();
    
    Date getDate();
    Date getLastModified();
    URI getLocation();
    Set<Link> getLinks();
    boolean hasLink(String relation);
    Link getLink(String relation);
    Link.Builder getLinkBuilder(String relation);
    
    boolean hasEntity();
    Object getEntity();
    Class<?> getEntityClass();
    Type getEntityType();
    void setEntity(Object entity);
    void setEntity(Object entity, Annotation[] annotations, MediaType mediaType);
    
    Annotation[] getEntityAnnotations();
    MediaType getMediaType();
    
    OutputStream getEntityStream();
    void setEntityStream(OutputStream outputStream);
}

Request and Response Filters

ContainerRequestFilter Interface

Filters incoming server requests.

@Provider
public interface ContainerRequestFilter {
    
    void filter(ContainerRequestContext requestContext) throws IOException;
}

ContainerResponseFilter Interface

Filters outgoing server responses.

@Provider
public interface ContainerResponseFilter {
    
    void filter(ContainerRequestContext requestContext,
                ContainerResponseContext responseContext) throws IOException;
}

Filter Implementation Examples:

// Authentication filter
@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        String authorization = requestContext.getHeaderString("Authorization");
        
        if (authorization == null || !authorization.startsWith("Bearer ")) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
                                           .entity("Authentication required")
                                           .build());
            return;
        }
        
        String token = authorization.substring("Bearer ".length());
        if (!isValidToken(token)) {
            requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED)
                                           .entity("Invalid token")
                                           .build());
        }
    }
    
    private boolean isValidToken(String token) {
        // Token validation logic
        return tokenService.validate(token);
    }
}

// Logging filter
@Provider
public class LoggingFilter implements ContainerRequestFilter, ContainerResponseFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        System.out.println("Request: " + requestContext.getMethod() + " " + 
                          requestContext.getUriInfo().getRequestUri());
        
        // Store request timestamp
        requestContext.setProperty("request.timestamp", System.currentTimeMillis());
    }
    
    @Override
    public void filter(ContainerRequestContext requestContext,
                      ContainerResponseContext responseContext) throws IOException {
        Long startTime = (Long) requestContext.getProperty("request.timestamp");
        long duration = System.currentTimeMillis() - startTime;
        
        System.out.println("Response: " + responseContext.getStatus() + 
                          " (took " + duration + "ms)");
    }
}

// CORS filter
@Provider
@PreMatching
public class CorsFilter implements ContainerRequestFilter, ContainerResponseFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        if ("OPTIONS".equals(requestContext.getMethod())) {
            requestContext.abortWith(Response.ok().build());
        }
    }
    
    @Override
    public void filter(ContainerRequestContext requestContext,
                      ContainerResponseContext responseContext) throws IOException {
        responseContext.getHeaders().add("Access-Control-Allow-Origin", "*");
        responseContext.getHeaders().add("Access-Control-Allow-Methods", 
                                        "GET, POST, PUT, DELETE, OPTIONS");
        responseContext.getHeaders().add("Access-Control-Allow-Headers", 
                                        "Content-Type, Authorization");
    }
}

@PreMatching Annotation

Marks filters to be executed before resource method matching.

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreMatching {
}

Pre-matching Filter Example:

@Provider
@PreMatching
@Priority(Priorities.HEADER_DECORATOR)
public class PreMatchingFilter implements ContainerRequestFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        // Modify request before resource matching
        String userAgent = requestContext.getHeaderString("User-Agent");
        if (userAgent != null && userAgent.contains("mobile")) {
            // Redirect mobile users to mobile API
            String uri = requestContext.getUriInfo().getRequestUri().toString();
            String mobileUri = uri.replace("/api/", "/mobile-api/");
            requestContext.setRequestUri(URI.create(mobileUri));
        }
    }
}

Dynamic Configuration

DynamicFeature Interface

Allows runtime configuration of providers based on resource information.

public interface DynamicFeature {
    
    void configure(ResourceInfo resourceInfo, FeatureContext context);
}

Dynamic Feature Example:

@Provider
public class SecurityDynamicFeature implements DynamicFeature {
    
    @Override
    public void configure(ResourceInfo resourceInfo, FeatureContext context) {
        Method method = resourceInfo.getResourceMethod();
        
        // Apply authentication filter only to methods annotated with @Secured
        if (method.isAnnotationPresent(Secured.class)) {
            context.register(AuthenticationFilter.class);
        }
        
        // Apply admin filter to admin methods
        if (method.isAnnotationPresent(AdminRequired.class)) {
            context.register(AdminAuthorizationFilter.class, Priorities.AUTHORIZATION);
        }
    }
}

// Custom security annotations
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Secured {
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface AdminRequired {
}

// Usage in resource
@Path("/admin")
public class AdminResource {
    
    @GET
    @Path("/users")
    @Secured
    @AdminRequired
    public List<User> getAllUsers() {
        return userService.findAll();
    }
}

FeatureContext Interface

Provides a context for configuring providers dynamically.

public interface FeatureContext extends Configurable<FeatureContext> {
    
    // Inherited from Configurable<FeatureContext>:
    Configuration getConfiguration();
    FeatureContext property(String name, Object value);
    FeatureContext register(Class<?> componentClass);
    FeatureContext register(Class<?> componentClass, int priority);
    FeatureContext register(Class<?> componentClass, Class<?>... contracts);
    FeatureContext register(Class<?> componentClass, Map<Class<?>, Integer> contracts);
    FeatureContext register(Object component);
    FeatureContext register(Object component, int priority);
    FeatureContext register(Object component, Class<?>... contracts);
    FeatureContext register(Object component, Map<Class<?>, Integer> contracts);
}

Asynchronous Processing

AsyncResponse Interface

Provides asynchronous response processing capabilities.

public interface AsyncResponse {
    
    boolean resume(Object response);
    boolean resume(Throwable response);
    
    boolean cancel();
    boolean cancel(int retryAfter);
    boolean cancel(Date retryAfter);
    
    boolean isSuspended();
    boolean isCancelled();
    boolean isDone();
    
    boolean setTimeout(long time, TimeUnit unit);
    void setTimeoutHandler(TimeoutHandler handler);
    
    Collection<Class<?>> register(Class<?> callback);
    Map<Class<?>, Collection<Class<?>>> register(Class<?> callback, Class<?>... callbacks);
    Collection<Class<?>> register(Object callback);
    Map<Class<?>, Collection<Class<?>>> register(Object callback, Object... callbacks);
}

@Suspended Annotation

Marks a parameter for AsyncResponse injection.

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Suspended {
}

Asynchronous Processing Examples:

@Path("/async")
public class AsyncResource {
    
    @Inject
    private ExecutorService executorService;
    
    // Simple async processing
    @GET
    @Path("/users/{id}")
    public void getUser(@PathParam("id") String userId,
                       @Suspended AsyncResponse asyncResponse) {
        
        executorService.submit(() -> {
            try {
                User user = userService.findById(userId);
                asyncResponse.resume(user);
            } catch (Exception e) {
                asyncResponse.resume(e);
            }
        });
    }
    
    // Async with timeout
    @GET
    @Path("/expensive-operation")
    public void expensiveOperation(@Suspended AsyncResponse asyncResponse) {
        
        // Set 30 second timeout
        asyncResponse.setTimeout(30, TimeUnit.SECONDS);
        asyncResponse.setTimeoutHandler(ar -> 
            ar.resume(Response.status(Response.Status.REQUEST_TIMEOUT)
                             .entity("Operation timed out")
                             .build())
        );
        
        executorService.submit(() -> {
            try {
                String result = performExpensiveOperation();
                asyncResponse.resume(Response.ok(result).build());
            } catch (Exception e) {
                asyncResponse.resume(Response.serverError()
                                           .entity("Operation failed")
                                           .build());
            }
        });
    }
    
    // Async with callbacks
    @POST
    @Path("/process")
    public void processData(DataRequest request,
                           @Suspended AsyncResponse asyncResponse) {
        
        // Register callbacks
        asyncResponse.register(CompletionCallback.class);
        asyncResponse.register(ConnectionCallback.class);
        
        CompletableFuture.supplyAsync(() -> dataProcessor.process(request))
                        .thenAccept(asyncResponse::resume)
                        .exceptionally(throwable -> {
                            asyncResponse.resume(throwable);
                            return null;
                        });
    }
}

Completion and Connection Callbacks

public interface CompletionCallback {
    
    void onComplete(Throwable throwable);
}

public interface ConnectionCallback {
    
    void onDisconnect(AsyncResponse disconnected);
}

TimeoutHandler Interface

public interface TimeoutHandler {
    
    void handleTimeout(AsyncResponse asyncResponse);
}

Callback Implementation Examples:

@Provider
public class AsyncCallbacks implements CompletionCallback, ConnectionCallback {
    
    @Override
    public void onComplete(Throwable throwable) {
        if (throwable == null) {
            System.out.println("Async operation completed successfully");
        } else {
            System.err.println("Async operation failed: " + throwable.getMessage());
        }
    }
    
    @Override
    public void onDisconnect(AsyncResponse disconnected) {
        System.out.println("Client disconnected, cancelling operation");
        // Cleanup resources, cancel background tasks, etc.
    }
}

// Custom timeout handler
public class CustomTimeoutHandler implements TimeoutHandler {
    
    @Override
    public void handleTimeout(AsyncResponse asyncResponse) {
        // Custom timeout response
        ErrorResponse error = new ErrorResponse("TIMEOUT", 
                                              "Request processing timed out");
        asyncResponse.resume(Response.status(Response.Status.REQUEST_TIMEOUT)
                                   .entity(error)
                                   .build());
    }
}

Resource Management

ResourceContext Interface

Injectable helper for creating and initializing resource instances.

public interface ResourceContext {
    
    <T> T getResource(Class<T> resourceClass);
    <T> T initResource(T resource);
}

ResourceInfo Interface

Injectable interface providing runtime information about matched resource method.

public interface ResourceInfo {
    
    Method getResourceMethod();
    Class<?> getResourceClass();
}

Resource Management Examples:

@Path("/composite")
public class CompositeResource {
    
    @Context
    private ResourceContext resourceContext;
    
    @GET
    @Path("/user-orders/{userId}")
    public Response getUserOrders(@PathParam("userId") String userId) {
        
        // Get other resource instances
        UserResource userResource = resourceContext.getResource(UserResource.class);
        OrderResource orderResource = resourceContext.getResource(OrderResource.class);
        
        // Use resources to build composite response
        User user = userResource.getUser(userId);
        List<Order> orders = orderResource.getUserOrders(userId);
        
        UserOrdersResponse response = new UserOrdersResponse(user, orders);
        return Response.ok(response).build();
    }
}

// Resource info usage in filter
@Provider
public class ResourceInfoFilter implements ContainerRequestFilter {
    
    @Context
    private ResourceInfo resourceInfo;
    
    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {
        Method method = resourceInfo.getResourceMethod();
        Class<?> resourceClass = resourceInfo.getResourceClass();
        
        System.out.println("Processing request for " + 
                          resourceClass.getSimpleName() + "." + method.getName());
        
        // Apply method-specific processing
        if (method.isAnnotationPresent(Audited.class)) {
            // Enable auditing for this request
            requestContext.setProperty("audit.enabled", true);
        }
    }
}

Name Binding

Name binding allows selective application of filters and interceptors.

Name Binding Example:

// Define name binding annotation
@NameBinding
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Compress {
}

// Filter bound to @Compress annotation
@Provider
@Compress
public class CompressionFilter implements ContainerResponseFilter {
    
    @Override
    public void filter(ContainerRequestContext requestContext,
                      ContainerResponseContext responseContext) throws IOException {
        
        String acceptEncoding = requestContext.getHeaderString("Accept-Encoding");
        if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
            // Apply gzip compression
            responseContext.getHeaders().add("Content-Encoding", "gzip");
            // Wrap output stream with GZIPOutputStream
        }
    }
}

// Apply to specific methods
@Path("/data")
public class DataResource {
    
    @GET
    @Path("/large")
    @Compress  // Compression filter will be applied
    public LargeDataSet getLargeData() {
        return dataService.getLargeDataSet();
    }
    
    @GET
    @Path("/small")
    // No compression for small responses
    public SmallData getSmallData() {
        return dataService.getSmallData();
    }
}

Priority Constants

JAX-RS provides priority constants for ordering filters and interceptors.

public final class Priorities {
    
    public static final int AUTHENTICATION = 1000;
    public static final int AUTHORIZATION = 2000;
    public static final int HEADER_DECORATOR = 3000;
    public static final int ENTITY_CODER = 4000;
    public static final int USER = 5000;
}

Priority Usage Example:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {
    // Executed first (lowest priority number)
}

@Provider 
@Priority(Priorities.AUTHORIZATION)
public class AuthorizationFilter implements ContainerRequestFilter {
    // Executed after authentication
}

@Provider
@Priority(Priorities.HEADER_DECORATOR)  
public class HeaderDecoratorFilter implements ContainerResponseFilter {
    // Executed for response processing
}

Install with Tessl CLI

npx tessl i tessl/maven-javax-ws-rs--javax-ws-rs-api

docs

client-api.md

core-types.md

extensions.md

index.md

resource-endpoints.md

server-container.md

server-sent-events.md

tile.json