//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//

= Migrating from Jetty 11.0.x to Jetty 12.0.x

[[java-version]]
== Required Java Version Changes

[cols="1,1", options="header"]
|===
| Jetty 11.0.x | Jetty 12.0.x
| Java 11 | Java 17
|===

[[maven-artifacts]]
== Maven Artifacts Changes

[cols="1a,1a", options="header"]
|===
| Jetty 11.0.x | Jetty 12.0.x
| org.eclipse.jetty.fcgi:**fcgi-client** | org.eclipse.jetty.fcgi:**jetty-fcgi-client**
| org.eclipse.jetty.fcgi:**fcgi-server** | org.eclipse.jetty.fcgi:**jetty-fcgi-server**
| org.eclipse.jetty.http2:**http2-client** | org.eclipse.jetty.http2:**jetty-http2-client**
| org.eclipse.jetty.http2:**http2-common** | org.eclipse.jetty.http2:**jetty-http2-common**
| org.eclipse.jetty.http2:**http2-hpack** | org.eclipse.jetty.http2:**jetty-http2-hpack**
| org.eclipse.jetty.http2:**http2-http-client-transport** | org.eclipse.jetty.http2:**jetty-http2-client-transport**
| org.eclipse.jetty.http2:**http2-server** | org.eclipse.jetty.http2:**jetty-http2-server**
| org.eclipse.jetty.http3:**http3-client** | org.eclipse.jetty.http3:**jetty-http3-client**
| org.eclipse.jetty.http3:**http3-common** | org.eclipse.jetty.http3:**jetty-http3-common**
| org.eclipse.jetty.http3:**http3-http-client-transport** | org.eclipse.jetty.http3:**jetty-http3-client-transport**
| org.eclipse.jetty.http3:**http3-qpack** | org.eclipse.jetty.http3:**jetty-http3-qpack**
| org.eclipse.jetty.http3:**http3-server** | org.eclipse.jetty.http3:**jetty-http3-server**
| org.eclipse.jetty:**jetty-osgi.*** | * org.eclipse.jetty:**jetty-osgi**
* org.eclipse.jetty.{ee-all}:**jetty-{ee-all}-osgi-***
| org.eclipse.jetty:**jetty-proxy** | * org.eclipse.jetty:**jetty-proxy**
* org.eclipse.jetty.{ee-all}:**jetty-{ee-all}-proxy**
| org.eclipse.jetty.quic:**quic-client** | org.eclipse.jetty.quic:**jetty-quic-client**
| org.eclipse.jetty.quic:**quic-common** | org.eclipse.jetty.quic:**jetty-quic-common**
| org.eclipse.jetty.quic:**quic-quiche** | org.eclipse.jetty.quic:**jetty-quic-quiche**
| org.eclipse.jetty.quic:**quic-server** | org.eclipse.jetty.quic:**jetty-quic-server**
| org.eclipse.jetty:**jetty-unixsocket.*** | Removed -- Use org.eclipse.jetty:jetty-unixdomain-server
| org.eclipse.jetty.websocket:**websocket-core-client** | org.eclipse.jetty.websocket:**jetty-websocket-core-client**
| org.eclipse.jetty.websocket:**websocket-core-common** | org.eclipse.jetty.websocket:**jetty-websocket-core-common**
| org.eclipse.jetty.websocket:**websocket-core-server** | org.eclipse.jetty.websocket:**jetty-websocket-core-server**
| org.eclipse.jetty.websocket:**websocket-jetty-api** | org.eclipse.jetty.websocket:**jetty-websocket-jetty-api**
| org.eclipse.jetty.websocket:**websocket-jetty-client** | * org.eclipse.jetty.websocket:**jetty-websocket-jetty-client**
* org.eclipse.jetty.**{ee-all}.websocket**:jetty-**{ee-all}-websocket-jetty-client**
| org.eclipse.jetty.websocket:**websocket-jetty-common** | * org.eclipse.jetty.websocket:**jetty-websocket-jetty-common**
* org.eclipse.jetty.**{ee-all}.websocket**:jetty-**{ee-all}-websocket-jetty-common**
| org.eclipse.jetty.websocket:**websocket-jetty-server** | * org.eclipse.jetty.websocket:**jetty-websocket-jetty-server**
* org.eclipse.jetty.**{ee-all}.websocket**:jetty-**{ee-all}-websocket-jetty-server**
| org.eclipse.jetty.**websocket**:**websocket-jakarta-client** | org.eclipse.jetty.**{ee-all}.websocket**:**jetty-{ee-all}-websocket-jakarta-client**
| org.eclipse.jetty.**websocket**:**websocket-jakarta-common** | org.eclipse.jetty.**{ee-all}.websocket**:**jetty-{ee-all}-websocket-jakarta-common**
| org.eclipse.jetty.**websocket**:**websocket-jakarta-server** | org.eclipse.jetty.**{ee-all}.websocket**:**jetty-{ee-all}-websocket-jakarta-server**
| org.eclipse.jetty.**websocket**:**websocket-servlet** | org.eclipse.jetty.**{ee-all}.websocket**:**jetty-{ee-all}-websocket-servlet**
| org.eclipse.jetty:**apache-jsp** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-apache-jsp**
| org.eclipse.jetty:**jetty-annotations** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-annotations**
| org.eclipse.jetty:**jetty-ant** | Removed -- No Replacement
| org.eclipse.jetty:**jetty-cdi** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-cdi**
| org.eclipse.jetty:**glassfish-jstl** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-glassfish-jstl**
| org.eclipse.jetty:**jetty-jaspi** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-jaspi**
| org.eclipse.jetty:**jetty-jndi** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-jndi**
| org.eclipse.jetty:**jetty-jspc-maven-plugin** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-jspc-maven-plugin**
| org.eclipse.jetty:**jetty-maven-plugin** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-maven-plugin**
| org.eclipse.jetty:**jetty-plus** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-plus**
| org.eclipse.jetty:**jetty-quickstart** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-quickstart**
| org.eclipse.jetty:**jetty-runner** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-runner**
| org.eclipse.jetty:**jetty-servlet** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-servlet**
| org.eclipse.jetty:**jetty-servlets** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-servlets**
| org.eclipse.jetty:**jetty-webapp** | org.eclipse.jetty.**{ee-all}**:**jetty-{ee-all}-webapp**
|===

[[class-packages-names]]
== Class Packages/Names Changes

[cols="1a,1a", options="header"]
|===
| Jetty 11.0.x | Jetty 12.0.x
| `org.eclipse.jetty.client.**api**.*` | `org.eclipse.jetty.client.*`
| `org.eclipse.jetty.client.**util**.*` | `org.eclipse.jetty.client.*`
| `org.eclipse.jetty.client.**util**.*` | `org.eclipse.jetty.client.*`
| `org.eclipse.jetty.client.**http**.*` | `org.eclipse.jetty.client.**transport**.*`
| `org.eclipse.jetty.http2.client.**http**.*` | `org.eclipse.jetty.http2.client.**transport**.*`

| `org.eclipse.jetty.websocket.api.annotation.**OnWebSocketConnect**` | `org.eclipse.jetty.websocket.api.annotation.**OnWebSocketOpen**`
| `org.eclipse.jetty.websocket.api.**WriteCallback**` | `org.eclipse.jetty.websocket.api.**Callback**`
| `org.eclipse.jetty.websocket.api.**WebSocket*Listener**` | `org.eclipse.jetty.websocket.api.**Session.Listener.AutoDemanding**`
| `org.eclipse.jetty.websocket.api.**RemoteEndpoint**` | `org.eclipse.jetty.websocket.api.**Session**`
| `org.eclipse.jetty.websocket.api.**WebSocketPolicy**` | `org.eclipse.jetty.websocket.api.**Configurable**`
|===

[[jetty-module-names]]
== Jetty Module Changes
[cols="1a,1a", options="header"]
|===
| Jetty 11.0.x | Jetty 12.0.x
| `annotations.mod` | `{ee-all}-annotations.mod` +
| `apache-jsp.mod` | `{ee-all}-apache-jsp.mod` +
| `bytebufferpool-logarithmic.mod` | `bytebufferpool-quadratic.mod`
| `cdi.mod` +
`cdi-*.mod` | `{ee-all}-cdi.mod` +
`{ee-all}-cdi-*.mod`
| `deploy.mod` | `core-deploy.mod` +
`{ee-all}-deploy.mod`
| `fcgi.mod` | `{ee-all}-fcgi-proxy.mod`
| `glassfish-jstl.mod` | `{ee-all}-glassfish-jstl.mod`
| `jaspi.mod` +
`jaspi-*.mod` | `{ee-all}-jaspi.mod` +
`{ee-all}-jaspi-*.mod`
| `jsp.mod` | `{ee-all}-jsp.mod`
| `jstl.mod` | `{ee-all}-jstl.mod`
| `openid.mod` | `openid.mod` +
`{ee-all}-openid.mod`
| `plus.mod` | `plus.mod` +
`{ee-all}-plus.mod`
| `proxy.mod` | `proxy.mod` +
`{ee-all}-proxy.mod`
| `security.mod` | `security.mod` +
`{ee-all}-security.mod`
| `servlet.mod` | `{ee-all}-servlet.mod`
| `servlets.mod` | `{ee-all}-servlets.mod`
| `stats.mod` | `statistics.mod`
| `webapp.mod` | `{ee-all}-webapp.mod`
| `websocket.mod` | N/A
| `websocket-jakarta.mod` | `{ee-all}-websocket-jakarta.mod`
| `websocket-jetty.mod` | `websocket-jetty.mod` +
`{ee-all}-websocket-jetty.mod`
|===

With the introduction of the <<jetty-core-apis,Jetty Core APIs>>, modules that in Jetty 11 were implicitly based on the Servlet APIs, in Jetty 12 have been renamed to `{ee-all}-<name>.mod`.

Modules that retain the same name, such as `openid.mod`, `security.mod`, etc., in Jetty 12 enable the same functionality using the Jetty Core APIs, not the Servlet APIs.
For the correspondent module that uses the Servlet API, use `{ee-all}-openid.mod`, `{ee-all}-security.mod`, etc.

This is particularly important for the Jetty 11 `deploy.mod`, that in Jetty 12 must be explicitly changed to one of the `{ee-all}-deploy.mod`, otherwise web applications will not be deployed.
Refer to xref:operations-guide:deploy/index.adoc[web application deployment] section for more information.

[[jetty-core-apis]]
== Server-Side Web Application APIs Changes

Jetty 12 introduced redesigned server-side APIs for web applications.
In Jetty 11, these APIs were based on a mix of Jakarta Servlet APIs and Jetty Handler APIs, while in Jetty 12 they are solely based on Jetty Handler APIs.

In Jetty 12 you can now write web applications independently of the Servlet APIs, so you can migrate Jakarta Servlets to Jetty Handlers as explained in xref:servlet-to-handler[this section].

If you were already using the Jetty 11 Handler APIs, you can migrate them to the Jetty 12 Handler APIs as explained in xref:api-changes-handler[this section].

[[servlet-to-handler]]
== Migrate Servlets to Jetty Handlers

Web applications written using the Servlet APIs may be re-written using the Jetty `Handler` APIs.
The sections below outline the Jetty `Handler` APIs that correspond to the Servlet APIs.
For more information about why using the Jetty `Handler` APIs instead of the Servlet APIs, refer to xref:server/http.adoc[this section].

For more information about replacing ``HttpServlet``s or Servlet ``Filter``s with Jetty ``Handler``s, refer to xref:server/http.adoc#handler[this section].

=== Handler Request APIs
[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=request]
----

=== Handler Request Content APIs
[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-string]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-buffer]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-stream]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-source]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-formFields]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=requestContent-multiPart]
----

Refer also to the `Content.Source` APIs detailed in xref:arch/io.adoc#content-source[this section].

=== Handler Response APIs
[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=response]
----

=== Handler Response Content APIs
[,java,indent=0]
----
include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-implicit]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-implicit-status]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-explicit]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-content]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-string]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-echo]

include::code:example$src/main/java/org/eclipse/jetty/docs/programming/migration/ServletToHandlerDocs.java[tags=responseContent-trailers]
----

Refer also to the `Content.Sink` APIs detailed in xref:arch/io.adoc#content-sink[this section].

[[api-changes]]
== APIs Changes

[[api-changes-handler]]
=== `Handler`

The server-side `Handler` class, and the APIs to use for request/response processing, have been redesigned in Jetty 12.

The Jetty 11 `Handler` method:

`Handler.handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)`

has been changed in Jetty 12 to:

`Handler.handle(Request request, Response response, Callback callback)`

The Jetty 11 `target` parameter has been removed, and in Jetty 12 it has been replaced by the information present in `Request.getHttpURI()`.

In Jetty 11, ``Handler``s would mark the fact that they handled the request, and therefore are producing a response, by calling `Request.setHandled(true)`.
In Jetty 12, this is performed by returning `true` from the `Handler.handle(\...)` method, which also requires that the `Callback` parameter must be completed, either by succeeding it or failing it.

In Jetty 11, the `Handler.handle(\...)` method has a blocking semantic, while in Jetty 12 the `Handler.handle(\...)` method has an asynchronous semantic, thanks to the `Callback` parameter.
This means that you can return from the `Handler.handle(\...)` method _before_ the response has been sent, similarly to what you can do with the Servlet APIs when you call `HttpServletRequest.startAsync()`.
Similarly, in Jetty 11 after a call to `startAsync()` you must call `AsyncContext.complete()`, while in Jetty 12 you must complete the `Callback` parameter, either by succeeding it or failing it.

In Jetty 11, `AbstractHandler` provides a utility class to implement `Handler`.
In Jetty 12, use `Handler.Abstract`.

In Jetty 11, the APIs to deal with request or response HTTP headers are based on either Jetty's `HttpFields`, or the Servlet APIs.
In Jetty 12, the HTTP headers API are only based on `HttpFields`.
Please refer to the `HttpFields` link:{javadoc-url}/org/eclipse/jetty/http/HttpFields.html[javadocs] for details.

In Jetty 11, the request content is accessed via `Request.getInputStream()` or `HttpServletRequest.getInputStream()`.
In Jetty 12, the `Request` object itself _is-a_ `Content.Source` that can be read as explained in xref:arch/io.adoc#content-source[this section].
In Jetty 12, you can use `Content.Source.asInputStream(request)` to obtain an `InputStream` and minimize the changes to your code, but remember that `InputStream` only provides blocking APIs, while `Content.Source` provides non-blocking APIs.

In Jetty 11, the response content is accessed via `Response.getOutputStream()` or `HttpServletResponse.getOutputStream()`.
In Jetty 12, the `Response` object itself _is-a_ `Content.Sink` that can be written as explained in xref:arch/io.adoc#content-sink[this section].
In Jetty 12, you can use `Content.Sink.asOutputStream(response)` to obtain an `OutputStream` and minimize the changes to your code, but remember that `OutputStream` only provides blocking APIs, while `Content.Sink` provides non-blocking APIs.

[[api-changes-handler-sequence]]
=== `HandlerCollection` and `HandlerList`

Jetty 11's `org.eclipse.jetty.server.handler.HandlerCollection` and `org.eclipse.jetty.server.handler.HandlerList` have been replaced by Jetty 12's `org.eclipse.jetty.server.Handler.Sequence`.

Note that when used in configuration properties, XML files, or via reflection, you must use the fully qualified class name `org.eclipse.jetty.server.Handler$Sequence` (note the `$` symbol).

Note that class `org.eclipse.jetty.server.handler.ContextHandlerCollection` has been retained (with the updates introduced by `Handler` as described <<api-changes-handler,here>>), and it is typically a better choice: where `Handler.Sequence` just iterates all its children ``Handler``s until one return `true` from the `handle(Request, Response, Callback)` method, `ContextHandlerCollection` more efficiently selects the child `ContextHandler` based on context path and virtual hosts.

[[api-changes-handler-requestlog]]
=== `RequestLogHandler`

Jetty 11's `org.eclipse.jetty.server.handler.RequestLogHandler` has been removed with no replacement.

In Jetty 12, request logging is achieved by calling `Server.setRequestLog(RequestLog requestLog)`, as described in xref:server/http.adoc#request-logging[this section].

=== `HttpClient`

The Jetty 11 `Request.onResponseContentDemanded(Response.DemandedContentListener)` API has been replaced by `Request.onResponseContentSource(Response.ContentSourceListener)` in Jetty 12.

However, also look at `Request.onResponseContentAsync(Response.AsyncContentListener)` and `Request.onResponseContent(Response.ContentListener)` for simpler usages.

The Jetty 11 model was a "demand+push" model: the application was demanding content; when the content was available, the implementation was pushing content to the application by calling `DemandedContentListener.onContent(Response, LongConsumer, ByteBuffer, Callback)` for every content chunk.

The Jetty 12 model is a "demand+pull" model: when the content is available, the implementation calls once `Response.ContentSourceListener.onContentSource(Content.Source)`; the application can then pull the content chunks from the `Content.Source`.

For more information about the new model, see xref:arch/io.adoc#content-source[this section].

Jetty 12 introduced the concept of low-level transport for high-level protocols, described in xref:client/io-arch.adoc#transport[this section].

=== WebSocket

The Jetty WebSocket APIs have been vastly simplified, and brought in line with the style of other APIs.

The Jetty 12 WebSocket APIs are now fully asynchronous, so the Jetty 11 `SuspendToken` class has been removed in favor of an explicit (or automatic) demand mechanism in Jetty 12 (for more information, refer to xref:client/websocket.adoc#endpoints-demand[this section]).

The various Jetty 11 `WebSocket*Listener` interfaces have been replaced by a single interface in Jetty 12, `Session.Listener.AutoDemanding` (for more information, refer to xref:client/websocket.adoc#endpoints-listener[this section]).

The Jetty 11 `RemoteEndpoint` APIs have been merged into the `Session` APIs in Jetty 12.

The Jetty 11 `WriteCallback` class has been renamed to just `Callback` in Jetty 12, because it is now also used when receiving binary data.
Note that this `Callback` interface is a different interface from the `org.eclipse.jetty.util.Callback` interface, which cannot be used in the Jetty WebSocket APIs due to class loader visibility issues.

On the server-side, the Jetty WebSocket APIs have been made independent of the Servlet APIs.

Jetty 11 `JettyWebSocketServerContainer` has been replaced by `ServerWebSocketContainer` in Jetty 12, with similar APIs (for more information, refer to xref:server/websocket.adoc#jetty[this section]).

On the client-side the `WebSocketClient` APIs are practically unchanged, as most of the changes come from the `HttpClient` changes described above.
