This guide explains the routing and interceptor mechanisms in JavaCommons-servlet. It clarifies the behaviors and technical differences between the library's core routing annotations (@ApiPath, @RequestPath), method constraints (@RequestType), and lifecycle hooks (@RequestBefore, @RequestAfter).
| Annotation | Primary Use-Case | Target Scope | HTTP Method Verification | Multi-Match Execution | Exception Handling |
|---|---|---|---|---|---|
@ApiPath |
Programmatic JSON APIs consumed by client web apps. Generates client JS. | Methods only | Enforced (filtered via @RequestType) |
No (first exact match wins) | Automated JSON wrap (returns structured JSON maps) |
@RequestPath |
Standard page-level & hierarchical sub-page routing. | Methods & Fields | Enforced (filtered via @RequestType) |
No (first exact match wins) | Raw propagation (escapes to servlet container) |
@RequestType |
HTTP method constraint (GET, POST, etc.) for a route. | Methods only | N/A (defines the allowed verbs) | N/A (declares allowed verbs list) | N/A |
@RequestBefore |
Pre-request hook (runs before target endpoint). | Methods only | Ignored (accepts all HTTP methods) | Yes (runs all matches in specificity order) | Inherits behavior of matching parent route |
@RequestAfter |
Post-request hook (runs after target endpoint). | Methods only | Ignored (accepts all HTTP methods) | Yes (runs all matches in specificity order) | Inherits behavior of matching parent route |
Designed for backend programmatic JSON endpoints.
- Frontend Integration: Automatically scanned by
AxiosApiBuilderto generate client-side JS wrapper functions (axiosApi.js), allowing frontend devs to call APIs natively (e.g.api.user.getProfile()). - Enforced Verb Filtering: Honors
@RequestTypefiltering. If an incoming request's HTTP verb does not match the@RequestTypeconstraints of the endpoint, it returns a404 Errorinstead of executing. - Automated Exception Handling: Any exception thrown is caught internally, wrapped into an
ApiException, and returned as a standard JSON error:{"ERROR": {"message": "Error details..."}}
Acts as a traditional HTTP route handler, similar to standard servlet mapping.
- Sub-Routers (Field Injection): Can target fields to build modular, hierarchical path structures:
@RequestPath("admin/*") private AdminPage adminRouter; // Mounts AdminPage routes under /admin/...
- Enforced Verb Filtering: Honors
@RequestTypefiltering. - Raw Exceptions: Standard runtime exceptions propagate directly to the servlet container (typically displaying 500 error pages or raw stack traces).
The @RequestType annotation restricts an endpoint to specific HTTP methods (e.g. GET, POST, PUT, DELETE).
@RequestPath("profile")
@RequestType("POST")
public void saveProfile(PrintWriter writer) { ... }- Fully Enforced on Route Handlers:
@RequestTypeis fully enforced when paired with either@RequestPathor@ApiPath. - Server-Side API Enforcement: If an incoming request to an
@ApiPathendpoint does not match its@RequestTypeconstraints (e.g., executing a POST-only endpoint using a GET request), the routing engine rejects the route and returns a404 Error. - Ignored on Interceptors:
@RequestBeforeand@RequestAfterdo not respect@RequestType. They execute on any matching request path regardless of the HTTP method used. - Default Behavior (Omitting
@RequestType): If@RequestTypeis omitted from an endpoint, it is open to all HTTP methods (GET, POST, PUT, DELETE, etc.).- Unit Test Verification: Both
@RequestPathand@ApiPathverb verification behaviors (including single, multiple, and omitted constraints) are validated in the library test suite underBasePage_requestType_test.java.
- Unit Test Verification: Both
You can map multiple distinct controller methods to the exact same route path by restricting each method with different HTTP verbs via @RequestType. This enables clean RESTful routing (e.g., mapping a GET request on /users to a list method, and a POST request on /users to a creation method).
@RequestPath("users")
@RequestType("GET")
public void listUsers() { ... }
@RequestPath("users")
@RequestType("POST")
public void createUser() { ... }- Duplicate Verbs Forbidden: You cannot map overlapping HTTP verbs on the same route path (e.g. registering two
GEThandlers on/users, or aGEThandler and a handler without any@RequestTypeconstraints). Doing so will cause the scanner to fail with anIllegalStateException: Duplicate endpoint registrationduring class map initialization. - Interceptors Apply Universally: Interceptors (
@RequestBeforeand@RequestAfter) registered on the endpoint path (e.g./users) are mapped using the::allwildcard suffix. They are executed on all requests matching that route path, completely ignoring the HTTP verb used.
Interceptors provide a powerful hook system to execute cross-cutting concerns (e.g., authentication, request logging, session management, or adding custom response headers).
@RequestBefore("admin/*")
public void checkAdminAuth(ApiResponseMap response) {
if (!isAdmin()) {
halt(); // Halts further execution instantly
}
}For any incoming request, the execution sequence is:
Unlike route handlers (where only the first match is chosen), the servlet engine finds all matching @RequestBefore / @RequestAfter hooks and executes every single one.
- Wildcards (e.g.
admin/*) and path templates (e.g.user/:id/*) are fully supported.
When multiple interceptors match a request, they are sorted using the library's sortEndpointList algorithm:
- Exact match segment (Weight 0) is prioritized over a path variable segment (e.g.
:id, Weight 1), which is prioritized over a wildcard segment (e.g.*, Weight 2). - Longer matched paths (more segments) are prioritized over shorter ones.
Important
Interceptors execute in order of specificity (most specific first, least specific last).
For a request to /admin/user/profile, the hook matching /admin/user/profile runs before /admin/*.
Interceptors support the same automatic parameter injection as routing methods, meaning you can request parameters such as PrintWriter, ServletRequestMap, ApiResponseMap, or HttpServletRequest directly in the method signature.
Calling halt() on the page instance inside a @RequestBefore hook throws a HaltException. This immediately interrupts the execution pipeline, preventing the target route handler and any subsequent hooks from running.