Foy honours the Jakarta Servlet 6.1 spec to the letter — your web.xml, your @WebServlet, your filters and listeners are ported as-is. This page lists the points where the environment differs.

Foy is at 0.1.0-SNAPSHOT and the official TCK passes around 90 % (see TCK status). Migration is not recommended in production until the listed gaps are closed.

From Tomcat

Tomcat Foy Note

server.xml (<Connector>, <Engine>, <Host>)

FoyChappeBoot.builder() + Chappe

Programmatic configuration. The connector is Chappe, mounted through ChappeMountPoint.

WEB-INF/web.xml

Identical

Read by WebXmlParser at startup.

@WebServlet, @WebFilter, @WebListener

Identical

Detected at compile time by APT — no runtime scan.

META-INF/web-fragment.xml

Identical

Likewise, merged with web.xml under metadata-complete.

Coyote (HTTP/1.1, HTTP/2)

Chappe

HTTP/1.1 + HTTP/2 + virtual threads.

Realm / AuthMethod

SecurityProvider (foy-api)

Implement io.vidocq.foy.spi.security.SecurityProvider. Basic Auth via BasicAuthenticator.

JNDI lookups (@Resource)

@Inject via foy-cdi-vauban

Datasources / pools are CDI Vauban beans.

Context.xml resources

CDI Vauban beans

// TODO@user: clarify mapping for application JNDI resources.

From Jetty (Servlet)

Jetty Foy Note

Server + ServerConnector

Chappe ChappeBoot

The connector is Chappe.

WebAppContext

FoyChappeBoot.builder().contextPath(…​)

// TODO@user: direct WAR deploy once stabilised.

ServletContextHandler

VidocqServletContext (internal)

Likewise.

JettyWebSocketServletContainerInitializer

// TODO@user

WebSocket Servlet 6.1 planned, no date.

Custom Jetty Handler

Chappe Handler

The io.vidocq.chappe.api.Handler API is the equivalent — see Chappe Reference.

From Undertow

Undertow Foy Note

Undertow.builder()

FoyChappeBoot.builder() + Chappe

Two-step programmatic config: Chappe for transport, Foy for Servlet.

DeploymentInfo

Automatic WebAppDiscovery through BeanManager

No explicit Servlet/Filter config — annotations + web.xml.

Undertow HttpHandler

Chappe Handler

See Chappe Reference.

From Helidon Servlet

// TODO@user: to document once a real-world migration case shows up.

Known gaps

  • WebSocket Servlet 6.1 / Jakarta WebSocket 2.2// TODO@user: planned, no date.

  • Cross-context dispatch (ServletContext.getContext) — not implemented, see TCK.

  • JSP — not supported, not planned. For dynamic pages use Cassini (REST) or HTML-emitting Servlets.

  • Form-based / Digest authentication// TODO@user: in progress.

Common pitfalls

  • No runtime META-INF/services autoload. Foy does not use ServiceLoader at startup. If a Servlet library relies on a ServletContainerInitializer loaded by scan, declare it as a CDI bean in Vauban.

  • metadata-complete=true honoured to the letter. With false, APT-detected annotations take precedence — standard Servlet 6.1 behaviour.

  • No runtime dynamic proxy. Frameworks that rely on it (Spring AOP, some profiling libs) won’t work as-is. Prefer APT alternatives (Vauban, Class-File API).

  • Strict JPMS modules. If a legacy uses reflective setAccessible(true), it needs an explicit --add-opens — better to port the legacy to @Inject.