Before diving into internals, let’s pin down the vocabulary. The terms below come from the Jakarta Servlet 6.1 spec as implemented by Foy.
Core vocabulary
| Term | Meaning in Foy |
|---|---|
Request / Response |
|
Servlet |
A |
Filter chain |
Pipeline of |
Listener |
A bean reacting to container lifecycle ( |
|
Implemented by |
|
|
Async |
|
Multipart |
|
Metaphor: the layer above the transport
Chappe moves bytes: it speaks HTTP/1.1 or HTTP/2 over TLS, manages a connection, reads a body. It does not know what a "Servlet" or a "filter" is.
Foy interprets those bytes: it turns an HTTP connection into an HttpServletRequest, finds the Servlet matching the URL, walks the filter chain, writes the response. It is exactly the division the 19th-century French telegraph administration drew between stationnaires (relaying the Chappe code without understanding it) and bureau directors (interpreting the message).
Application discovery
foy-core orchestrates the merge between annotations and descriptors:
-
reading of annotations (
@WebServlet,@WebFilter,@WebListener,@MultipartConfig) — resolved at compile time by an APT, exposed through the VaubanBeanManager; -
reading of descriptors (
WEB-INF/web.xml,META-INF/web-fragment.xml) viaWebXmlParser, producing aWebAppDescriptor; -
merge under
metadata-complete(standard Servlet 6.1); -
WebAppDiscoveryperforms the aggregation atFoyChappeBootstartup.
No runtime classpath scan. All Servlet beans are already known to Vauban at compile time.
Chappe ↔ Servlet bridge
foy-chappe hosts ChappeServletBridge, a Chappe Handler that:
-
exposes the Chappe
RequestasHttpServletRequestImpl; -
exposes the Chappe
ResponseasHttpServletResponseImpl; -
invokes the
Filter→Servletchain; -
returns the Chappe
Bodybuilt aroundServletOutputStreamImpl.
The Servlet OutputStream is wired directly to Chappe streaming — no body copy, no intermediate buffer.
Application security
-
BasicAuthenticator— standard HTTP Basic (RFC 7617). -
SecurityConstraintEnforcer— applies<security-constraint>fromweb.xml. -
AnonymousSecurityProvider— open fallback for development. -
Public SPI:
io.vidocq.foy.spi.security.SecurityProviderfor plugging custom providers (LDAP, JWT, OIDC).
Form-based and Digest: // TODO@user: document once stable. Jakarta Authentication / Authorization: // TODO@user: planned, later milestone.
CDI: a single BeanManager
foy-cdi-vauban grafts the Servlet API onto Vauban:
-
ServletContextis exposed as@ApplicationScoped; -
HttpServletRequestas@RequestScoped; -
HttpSessionas@SessionScoped(// TODO@user: confirm M2 availability); -
Servlet/Filtercan carry@Inject.
Resolution is fully build-time through Vauban — no dynamic proxy, no hot-path reflection, AOT-friendly (GraalVM, Leyden CDS).
Servlet 6.1 vs 5.0 differences
| Aspect | Servlet 5.0 (Jakarta EE 9.1) | Servlet 6.1 (Jakarta EE 11) |
|---|---|---|
Package |
|
|
JPMS modules |
Optional |
Recommended — Foy enforces it |
I/O threading |
Platform pool + NIO |
Virtual threads (Foy: one VT per request) |
Legacy API |
|
Removed / clarified |
WebSocket |
Separate spec 2.1 |
Separate spec 2.2 — |
HTTP/3 |
Out of scope |
Out of scope (transport — see Chappe) |
Foy focuses on the relevant 2026 subset: no JSP, no runtime SCI through META-INF/services, no reflection. Libraries that depended on those features need to be ported through an explicit SPI or an APT.