diff --git a/.github/renovate.json b/.github/renovate.json
index aab994ad8187..1f023c99f4f5 100644
--- a/.github/renovate.json
+++ b/.github/renovate.json
@@ -91,17 +91,6 @@
         "org.jfree:jfreechart"
       ]
     },
-    {
-      "description": "Starting with 6.x, Spring requires Java 17 at a minimum.",
-      "matchManagers": [
-        "maven"
-      ],
-      "allowedVersions": "<6.0.0",
-      "matchPackageNames": [
-        "org.springframework:spring-framework-bom",
-        "org.springframework.security:spring-security-bom"
-      ]
-    },
     {
       "description": "Starting with 7.x, Guice switches from javax.* to jakarta.* bindings. See https://github.com/google/guice/wiki/Guice700",
       "matchManagers": [
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
index ca018ebc3ab9..68f564fff79d 100644
--- a/.idea/encodings.xml
+++ b/.idea/encodings.xml
@@ -29,12 +29,9 @@
     <file url="file://$PROJECT_DIR$/war/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/war/src/main/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/war/src/test/java" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty10/src/filter/resources" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty10/src/main/java" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty10/src/main/resources" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee8/src/filter/resources" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee8/src/main/java" charset="UTF-8" />
-    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee8/src/main/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee9/src/filter/resources" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee9/src/main/java" charset="UTF-8" />
+    <file url="file://$PROJECT_DIR$/websocket/jetty12-ee9/src/main/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/websocket/spi/src/filter/resources" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/websocket/spi/src/main/java" charset="UTF-8" />
     <file url="file://$PROJECT_DIR$/websocket/spi/src/main/resources" charset="UTF-8" />
diff --git a/bom/pom.xml b/bom/pom.xml
index adf65f6cf439..cd55b58d52c9 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -39,7 +39,7 @@ THE SOFTWARE.
 
   <properties>
     <commons-fileupload2.version>2.0.0-M2</commons-fileupload2.version>
-    <stapler.version>1896.v8170998149d0</stapler.version>
+    <stapler.version>1903.v994a_db_314d58</stapler.version>
     <groovy.version>2.4.21</groovy.version>
   </properties>
 
@@ -62,15 +62,15 @@ THE SOFTWARE.
       <dependency>
         <groupId>org.springframework</groupId>
         <artifactId>spring-framework-bom</artifactId>
-        <version>5.3.39</version>
+        <version>6.1.12</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
       <dependency>
-        <!-- https://docs.spring.io/spring-security/site/docs/5.5.4/reference/html5/#getting-maven-no-boot -->
+        <!-- https://docs.spring.io/spring-security/reference/6.3/getting-spring-security.html#getting-maven-no-boot -->
         <groupId>org.springframework.security</groupId>
         <artifactId>spring-security-bom</artifactId>
-        <version>5.8.14</version>
+        <version>6.3.3</version>
         <type>pom</type>
         <scope>import</scope>
       </dependency>
@@ -154,12 +154,12 @@ THE SOFTWARE.
       <dependency>
         <groupId>jakarta.servlet</groupId>
         <artifactId>jakarta.servlet-api</artifactId>
-        <version>4.0.4</version>
+        <version>5.0.0</version>
       </dependency>
       <dependency>
         <groupId>jakarta.servlet.jsp.jstl</groupId>
         <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
-        <version>1.2.7</version>
+        <version>2.0.0</version>
       </dependency>
       <dependency>
         <groupId>jaxen</groupId>
@@ -295,7 +295,7 @@ THE SOFTWARE.
       <dependency>
         <groupId>org.jvnet.hudson</groupId>
         <artifactId>commons-jelly-tags-define</artifactId>
-        <version>1.1-jenkins-20240510</version>
+        <version>1.1-jenkins-20240903</version>
       </dependency>
       <dependency>
         <groupId>org.jvnet.localizer</groupId>
diff --git a/core/pom.xml b/core/pom.xml
index 8e30ae211ed7..9bff5e5ad0b2 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -217,6 +217,20 @@ THE SOFTWARE.
       <!-- needed by Jelly -->
       <groupId>jakarta.servlet.jsp.jstl</groupId>
       <artifactId>jakarta.servlet.jsp.jstl-api</artifactId>
+      <exclusions>
+        <exclusion>
+          <groupId>jakarta.el</groupId>
+          <artifactId>jakarta.el-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>jakarta.servlet</groupId>
+          <artifactId>jakarta.servlet-api</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>jakarta.xml.bind</groupId>
+          <artifactId>jakarta.xml.bind-api</artifactId>
+        </exclusion>
+      </exclusions>
     </dependency>
     <dependency>
       <groupId>jaxen</groupId>
@@ -288,7 +302,7 @@ THE SOFTWARE.
     </dependency>
     <dependency>
       <groupId>org.apache.commons</groupId>
-      <artifactId>commons-fileupload2-javax</artifactId>
+      <artifactId>commons-fileupload2-jakarta-servlet5</artifactId>
     </dependency>
     <dependency>
       <groupId>org.codehaus.groovy</groupId>
@@ -427,6 +441,10 @@ THE SOFTWARE.
       <groupId>org.springframework.security</groupId>
       <artifactId>spring-security-web</artifactId>
       <exclusions>
+        <exclusion>
+          <groupId>io.micrometer</groupId>
+          <artifactId>micrometer-observation</artifactId>
+        </exclusion>
         <exclusion>
           <groupId>org.springframework</groupId>
           <artifactId>spring-jcl</artifactId>
diff --git a/core/src/main/java/hudson/DescriptorExtensionList.java b/core/src/main/java/hudson/DescriptorExtensionList.java
index c92b6ae206c0..c658c83fe1fc 100644
--- a/core/src/main/java/hudson/DescriptorExtensionList.java
+++ b/core/src/main/java/hudson/DescriptorExtensionList.java
@@ -145,7 +145,7 @@ public T newInstanceFromRadioList(JSONObject config) throws FormException {
         if (config.isNullObject())
             return null;    // none was selected
         int idx = config.getInt("value");
-        return get(idx).newInstance(Stapler.getCurrentRequest(), config);
+        return get(idx).newInstance(Stapler.getCurrentRequest2(), config);
     }
 
     /**
diff --git a/core/src/main/java/hudson/ExpressionFactory2.java b/core/src/main/java/hudson/ExpressionFactory2.java
index 7fcec22e7604..1bc99160439b 100644
--- a/core/src/main/java/hudson/ExpressionFactory2.java
+++ b/core/src/main/java/hudson/ExpressionFactory2.java
@@ -12,7 +12,7 @@
 import org.apache.commons.jelly.expression.ExpressionSupport;
 import org.apache.commons.jexl.JexlContext;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.access.AccessDeniedException;
 
 /**
@@ -78,7 +78,7 @@ public Object evaluate(JellyContext context) {
                 // let the security exception pass through
                 throw e;
             } catch (Exception e) {
-                StaplerRequest currentRequest = Stapler.getCurrentRequest();
+                StaplerRequest2 currentRequest = Stapler.getCurrentRequest2();
                 LOGGER.log(Level.WARNING, "Caught exception evaluating: " + expression + " in " + (currentRequest != null ? currentRequest.getOriginalRequestURI() : "?") + ". Reason: " + e, e);
                 return null;
             } finally {
diff --git a/core/src/main/java/hudson/FilePath.java b/core/src/main/java/hudson/FilePath.java
index 06773dd9a9ee..f5288b26d9d1 100644
--- a/core/src/main/java/hudson/FilePath.java
+++ b/core/src/main/java/hudson/FilePath.java
@@ -3510,7 +3510,7 @@ public FormValidation validateRelativePath(String value, boolean errorIfNotExist
     }
 
     private static void checkPermissionForValidate() {
-        AccessControlled subject = Stapler.getCurrentRequest().findAncestorObject(AbstractProject.class);
+        AccessControlled subject = Stapler.getCurrentRequest2().findAncestorObject(AbstractProject.class);
         if (subject == null)
             Jenkins.get().checkPermission(Jenkins.MANAGE);
         else
diff --git a/core/src/main/java/hudson/Functions.java b/core/src/main/java/hudson/Functions.java
index cd25f9bc9871..d2b62e99a2f2 100644
--- a/core/src/main/java/hudson/Functions.java
+++ b/core/src/main/java/hudson/Functions.java
@@ -95,6 +95,14 @@
 import hudson.views.MyViewsTabBar;
 import hudson.views.ViewsTabBar;
 import hudson.widgets.RenderOnDemandClosure;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import io.jenkins.servlet.http.CookieWrapper;
+import io.jenkins.servlet.http.HttpServletRequestWrapper;
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
@@ -148,10 +156,6 @@
 import java.util.logging.SimpleFormatter;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import javax.servlet.ServletException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.console.ConsoleUrlProvider;
 import jenkins.model.GlobalConfiguration;
 import jenkins.model.GlobalConfigurationCategory;
@@ -176,7 +180,9 @@
 import org.kohsuke.stapler.RawHtmlArgument;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.access.AccessDeniedException;
 
 /**
@@ -276,8 +282,8 @@ public static boolean isExtensionsAvailable() {
     }
 
     public static void initPageVariables(JellyContext context) {
-        StaplerRequest currentRequest = Stapler.getCurrentRequest();
-        currentRequest.getWebApp().getDispatchValidator().allowDispatch(currentRequest, Stapler.getCurrentResponse());
+        StaplerRequest2 currentRequest = Stapler.getCurrentRequest2();
+        currentRequest.getWebApp().getDispatchValidator().allowDispatch(currentRequest, Stapler.getCurrentResponse2());
         String rootURL = currentRequest.getContextPath();
 
         Functions h = new Functions();
@@ -372,7 +378,10 @@ public static String addSuffix(int n, String singular, String plural) {
         return buf.toString();
     }
 
-    public static RunUrl decompose(StaplerRequest req) {
+    /**
+     * @since TODO
+     */
+    public static RunUrl decompose(StaplerRequest2 req) {
         List<Ancestor> ancestors = req.getAncestors();
 
         // find the first and last Run instances
@@ -405,12 +414,20 @@ public static RunUrl decompose(StaplerRequest req) {
         return new RunUrl((Run) f.getObject(), head, base, rest);
     }
 
+    /**
+     * @deprecated use {@link #decompose(StaplerRequest2)}
+     */
+    @Deprecated
+    public static RunUrl decompose(StaplerRequest req) {
+        return decompose(StaplerRequest.toStaplerRequest2(req));
+    }
+
     /**
      * If we know the user's screen resolution, return it. Otherwise null.
      * @since 1.213
      */
     public static Area getScreenResolution() {
-        Cookie res = Functions.getCookie(Stapler.getCurrentRequest(), "screenResolution");
+        Cookie res = Functions.getCookie(Stapler.getCurrentRequest2(), "screenResolution");
         if (res != null)
             return Area.parse(res.getValue());
         return null;
@@ -592,6 +609,9 @@ public static <T> Iterable<T> reverse(Collection<T> collection) {
         return list;
     }
 
+    /**
+     * @since TODO
+     */
     public static Cookie getCookie(HttpServletRequest req, String name) {
         Cookie[] cookies = req.getCookies();
         if (cookies != null) {
@@ -604,12 +624,31 @@ public static Cookie getCookie(HttpServletRequest req, String name) {
         return null;
     }
 
+    /**
+     * @deprecated use {@link #getCookie(HttpServletRequest, String)}
+     */
+    @Deprecated
+    public static javax.servlet.http.Cookie getCookie(javax.servlet.http.HttpServletRequest req, String name) {
+        return CookieWrapper.fromJakartaServletHttpCookie(getCookie(HttpServletRequestWrapper.toJakartaHttpServletRequest(req), name));
+    }
+
+    /**
+     * @since TODO
+     */
     public static String getCookie(HttpServletRequest req, String name, String defaultValue) {
         Cookie c = getCookie(req, name);
         if (c == null || c.getValue() == null) return defaultValue;
         return c.getValue();
     }
 
+    /**
+     * @deprecated use {@link #getCookie(HttpServletRequest, String, String)}
+     */
+    @Deprecated
+    public static String getCookie(javax.servlet.http.HttpServletRequest req, String name, String defaultValue) {
+        return getCookie(HttpServletRequestWrapper.toJakartaHttpServletRequest(req), name, defaultValue);
+    }
+
     private static final Pattern ICON_SIZE = Pattern.compile("\\d+x\\d+");
 
     @Restricted(NoExternalUse.class)
@@ -713,8 +752,10 @@ public static long getHourLocalTimezone() {
      * Finds the given object in the ancestor list and returns its URL.
      * This is used to determine the "current" URL assigned to the given object,
      * so that one can compute relative URLs from it.
+     *
+     * @since TODO
      */
-    public static String getNearestAncestorUrl(StaplerRequest req, Object it) {
+    public static String getNearestAncestorUrl(StaplerRequest2 req, Object it) {
         List list = req.getAncestors();
         for (int i = list.size() - 1; i >= 0; i--) {
             Ancestor anc = (Ancestor) list.get(i);
@@ -724,11 +765,19 @@ public static String getNearestAncestorUrl(StaplerRequest req, Object it) {
         return null;
     }
 
+    /**
+     * @deprecated use {@link #getNearestAncestorUrl(StaplerRequest2, Object)}
+     */
+    @Deprecated
+    public static String getNearestAncestorUrl(StaplerRequest req, Object it) {
+        return getNearestAncestorUrl(StaplerRequest.toStaplerRequest2(req), it);
+    }
+
     /**
      * Finds the inner-most {@link SearchableModelObject} in scope.
      */
     public static String getSearchURL() {
-        List list = Stapler.getCurrentRequest().getAncestors();
+        List list = Stapler.getCurrentRequest2().getAncestors();
         for (int i = list.size() - 1; i >= 0; i--) {
             Ancestor anc = (Ancestor) list.get(i);
             if (anc.getObject() instanceof SearchableModelObject)
@@ -888,7 +937,7 @@ public static void checkPermission(Object object, Permission permission) throws
         if (object instanceof AccessControlled)
             checkPermission((AccessControlled) object, permission);
         else {
-            List<Ancestor> ancs = Stapler.getCurrentRequest().getAncestors();
+            List<Ancestor> ancs = Stapler.getCurrentRequest2().getAncestors();
             for (Ancestor anc : Iterators.reverse(ancs)) {
                 Object o = anc.getObject();
                 if (o instanceof AccessControlled) {
@@ -920,7 +969,7 @@ public static boolean hasPermission(Object object, Permission permission) throws
         if (object instanceof AccessControlled)
             return ((AccessControlled) object).hasPermission(permission);
         else {
-            List<Ancestor> ancs = Stapler.getCurrentRequest().getAncestors();
+            List<Ancestor> ancs = Stapler.getCurrentRequest2().getAncestors();
             for (Ancestor anc : Iterators.reverse(ancs)) {
                 Object o = anc.getObject();
                 if (o instanceof AccessControlled) {
@@ -931,10 +980,13 @@ public static boolean hasPermission(Object object, Permission permission) throws
         }
     }
 
-    public static void adminCheck(StaplerRequest req, StaplerResponse rsp, Object required, Permission permission) throws IOException, ServletException {
+    /**
+     * @since TODO
+     */
+    public static void adminCheck(StaplerRequest2 req, StaplerResponse2 rsp, Object required, Permission permission) throws IOException, ServletException {
         // this is legacy --- all views should be eventually converted to
         // the permission based model.
-        if (required != null && !Hudson.adminCheck(req, rsp)) {
+        if (required != null && !Hudson.adminCheck(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp))) {
             // check failed. commit the FORBIDDEN response, then abort.
             rsp.setStatus(HttpServletResponse.SC_FORBIDDEN);
             rsp.getOutputStream().close();
@@ -946,10 +998,24 @@ public static void adminCheck(StaplerRequest req, StaplerResponse rsp, Object re
             checkPermission(permission);
     }
 
+   /**
+     * @deprecated use {@link #adminCheck(StaplerRequest2, StaplerResponse2, Object, Permission)}
+     */
+    @Deprecated
+    public static void adminCheck(StaplerRequest req, StaplerResponse rsp, Object required, Permission permission) throws IOException, javax.servlet.ServletException {
+        try {
+            adminCheck(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), required, permission);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Infers the hudson installation URL from the given request.
+     *
+     * @since TODO
      */
-    public static String inferHudsonURL(StaplerRequest req) {
+    public static String inferHudsonURL(StaplerRequest2 req) {
         String rootUrl = Jenkins.get().getRootUrl();
         if (rootUrl != null)
             // prefer the one explicitly configured, to work with load-balancer, frontend, etc.
@@ -963,6 +1029,14 @@ public static String inferHudsonURL(StaplerRequest req) {
         return buf.toString();
     }
 
+    /**
+     * @deprecated use {@link #inferHudsonURL(StaplerRequest2)}
+     */
+    @Deprecated
+    public static String inferHudsonURL(StaplerRequest req) {
+        return inferHudsonURL(StaplerRequest.toStaplerRequest2(req));
+    }
+
     /**
      * Returns the link to be displayed in the footer of the UI.
      */
@@ -1226,7 +1300,7 @@ public static boolean hasAnyPermission(Object object, Permission[] permissions)
         if (object instanceof AccessControlled)
             return hasAnyPermission((AccessControlled) object, permissions);
         else {
-            AccessControlled ac = Stapler.getCurrentRequest().findAncestorObject(AccessControlled.class);
+            AccessControlled ac = Stapler.getCurrentRequest2().findAncestorObject(AccessControlled.class);
             if (ac != null) {
                 return hasAnyPermission(ac, permissions);
             }
@@ -1264,7 +1338,7 @@ public static void checkAnyPermission(Object object, Permission[] permissions) t
         if (object instanceof AccessControlled)
             checkAnyPermission((AccessControlled) object, permissions);
         else {
-            List<Ancestor> ancs = Stapler.getCurrentRequest().getAncestors();
+            List<Ancestor> ancs = Stapler.getCurrentRequest2().getAncestors();
             for (Ancestor anc : Iterators.reverse(ancs)) {
                 Object o = anc.getObject();
                 if (o instanceof AccessControlled) {
@@ -1335,7 +1409,7 @@ public static String getRelativeLinkTo(Item p) {
         Map<Object, String> ancestors = new HashMap<>();
         View view = null;
 
-        StaplerRequest request = Stapler.getCurrentRequest();
+        StaplerRequest2 request = Stapler.getCurrentRequest2();
         for (Ancestor a : request.getAncestors()) {
             ancestors.put(a.getObject(), a.getRelativePath());
             if (a.getObject() instanceof View)
@@ -1681,7 +1755,7 @@ public static String getViewResource(Object it, String path) {
         if (it instanceof Descriptor)
             clazz = ((Descriptor) it).clazz;
 
-        String buf = Stapler.getCurrentRequest().getContextPath() + Jenkins.VIEW_RESOURCE_PATH + '/' +
+        String buf = Stapler.getCurrentRequest2().getContextPath() + Jenkins.VIEW_RESOURCE_PATH + '/' +
                 clazz.getName().replace('.', '/').replace('$', '/') +
                 '/' + path;
         return buf;
@@ -1689,7 +1763,7 @@ public static String getViewResource(Object it, String path) {
 
     public static boolean hasView(Object it, String path) throws IOException {
         if (it == null)    return false;
-        return Stapler.getCurrentRequest().getView(it, path) != null;
+        return Stapler.getCurrentRequest2().getView(it, path) != null;
     }
 
     /**
@@ -1900,10 +1974,10 @@ public static String joinPath(String... components) {
             return null;
         }
         if (urlName.startsWith("/"))
-            return joinPath(Stapler.getCurrentRequest().getContextPath(), urlName);
+            return joinPath(Stapler.getCurrentRequest2().getContextPath(), urlName);
         else
             // relative URL name
-            return joinPath(Stapler.getCurrentRequest().getContextPath() + '/' + itUrl, urlName);
+            return joinPath(Stapler.getCurrentRequest2().getContextPath() + '/' + itUrl, urlName);
     }
 
     /**
@@ -1966,7 +2040,7 @@ public String getServerName() {
         } catch (MalformedURLException e) {
             // fall back to HTTP request
         }
-        return Stapler.getCurrentRequest().getServerName();
+        return Stapler.getCurrentRequest2().getServerName();
     }
 
     /**
@@ -2004,7 +2078,7 @@ public void calcCheckUrl(Map attributes, String userDefined, Object descriptor,
      * Used in {@code task.jelly} to decide if the page should be highlighted.
      */
     public boolean hyperlinkMatchesCurrentPage(String href) {
-        String url = Stapler.getCurrentRequest().getRequestURL().toString();
+        String url = Stapler.getCurrentRequest2().getRequestURL().toString();
         if (href == null || href.length() <= 1) return ".".equals(href) && url.endsWith("/");
         url = URLDecoder.decode(url, StandardCharsets.UTF_8);
         href = URLDecoder.decode(href, StandardCharsets.UTF_8);
@@ -2063,12 +2137,23 @@ public static List<Descriptor<CrumbIssuer>> getCrumbIssuerDescriptors() {
         return CrumbIssuer.all();
     }
 
-    public static String getCrumb(StaplerRequest req) {
+    /**
+     * @since TODO
+     */
+    public static String getCrumb(StaplerRequest2 req) {
         Jenkins h = Jenkins.getInstanceOrNull();
         CrumbIssuer issuer = h != null ? h.getCrumbIssuer() : null;
         return issuer != null ? issuer.getCrumb(req) : "";
     }
 
+    /**
+     * @deprecated use {@link #getCrumb(StaplerRequest2)}
+     */
+    @Deprecated
+    public static String getCrumb(StaplerRequest req) {
+        return getCrumb(req != null ? StaplerRequest.toStaplerRequest2(req) : null);
+    }
+
     public static String getCrumbRequestField() {
         Jenkins h = Jenkins.getInstanceOrNull();
         CrumbIssuer issuer = h != null ? h.getCrumbIssuer() : null;
@@ -2081,7 +2166,7 @@ public static Date getCurrentTime() {
 
     public static Locale getCurrentLocale() {
         Locale locale = null;
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req != null)
             locale = req.getLocale();
         if (locale == null)
@@ -2094,7 +2179,7 @@ public static Locale getCurrentLocale() {
      * from {@link ConsoleAnnotatorFactory}s and {@link ConsoleAnnotationDescriptor}s.
      */
     public static String generateConsoleAnnotationScriptAndStylesheet() {
-        String cp = Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH;
+        String cp = Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH;
         StringBuilder buf = new StringBuilder();
         for (ConsoleAnnotatorFactory f : ConsoleAnnotatorFactory.all()) {
             String path = cp + "/extensionList/" + ConsoleAnnotatorFactory.class.getName() + "/" + f.getClass().getName();
@@ -2147,7 +2232,7 @@ public String getPasswordValue(Object o) {
         }
 
         /* Mask from Extended Read */
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (o instanceof Secret || Secret.BLANK_NONSECRET_PASSWORD_FIELDS_WITHOUT_ITEM_CONFIGURE) {
             if (req != null) {
                 Item item = req.findAncestorObject(Item.class);
@@ -2243,15 +2328,17 @@ public static boolean isWipeOutPermissionEnabled() {
 
     @Deprecated
     public static String createRenderOnDemandProxy(JellyContext context, String attributesToCapture) {
-        return Stapler.getCurrentRequest().createJavaScriptProxy(new RenderOnDemandClosure(context, attributesToCapture));
+        return Stapler.getCurrentRequest2().createJavaScriptProxy(new RenderOnDemandClosure(context, attributesToCapture));
     }
 
     /**
      * Called from renderOnDemand.jelly to generate the parameters for the proxy object generation.
+     *
+     * @since TODO
      */
     @Restricted(NoExternalUse.class)
-    public static StaplerRequest.RenderOnDemandParameters createRenderOnDemandProxyParameters(JellyContext context, String attributesToCapture) {
-        return Stapler.getCurrentRequest().createJavaScriptProxyParameters(new RenderOnDemandClosure(context, attributesToCapture));
+    public static StaplerRequest2.RenderOnDemandParameters createRenderOnDemandProxyParameters(JellyContext context, String attributesToCapture) {
+        return Stapler.getCurrentRequest2().createJavaScriptProxyParameters(new RenderOnDemandClosure(context, attributesToCapture));
     }
 
     public static String getCurrentDescriptorByNameUrl() {
@@ -2260,18 +2347,18 @@ public static String getCurrentDescriptorByNameUrl() {
 
     public static String setCurrentDescriptorByNameUrl(String value) {
         String o = getCurrentDescriptorByNameUrl();
-        Stapler.getCurrentRequest().setAttribute("currentDescriptorByNameUrl", value);
+        Stapler.getCurrentRequest2().setAttribute("currentDescriptorByNameUrl", value);
 
         return o;
     }
 
     public static void restoreCurrentDescriptorByNameUrl(String old) {
-        Stapler.getCurrentRequest().setAttribute("currentDescriptorByNameUrl", old);
+        Stapler.getCurrentRequest2().setAttribute("currentDescriptorByNameUrl", old);
     }
 
     public static List<String> getRequestHeaders(String name) {
         List<String> r = new ArrayList<>();
-        Enumeration e = Stapler.getCurrentRequest().getHeaders(name);
+        Enumeration e = Stapler.getCurrentRequest2().getHeaders(name);
         while (e.hasMoreElements()) {
             r.add(e.nextElement().toString());
         }
@@ -2366,6 +2453,7 @@ public static String breakableString(final String plain) {
      * Advertises the minimum set of HTTP headers that assist programmatic
      * discovery of Jenkins.
      */
+    @SuppressFBWarnings(value = "UC_USELESS_VOID_METHOD", justification = "TODO needs triage")
     public static void advertiseHeaders(HttpServletResponse rsp) {
         Jenkins j = Jenkins.getInstanceOrNull();
         if (j != null) {
@@ -2375,6 +2463,14 @@ public static void advertiseHeaders(HttpServletResponse rsp) {
         }
     }
 
+    /**
+     * @deprecated use {@link #advertiseHeaders(HttpServletResponse)}
+     */
+    @Deprecated
+    public static void advertiseHeaders(javax.servlet.http.HttpServletResponse rsp) {
+        advertiseHeaders(HttpServletResponseWrapper.toJakartaHttpServletResponse(rsp));
+    }
+
     @Restricted(NoExternalUse.class) // for actions.jelly and ContextMenu.add
     public static boolean isContextMenuVisible(Action a) {
         if (a instanceof ModelObjectWithContextMenu.ContextMenuVisibility) {
@@ -2449,7 +2545,7 @@ public static String tryGetIconPath(String iconGuess, JellyContext context) {
             return iconGuess;
         }
 
-        StaplerRequest currentRequest = Stapler.getCurrentRequest();
+        StaplerRequest2 currentRequest = Stapler.getCurrentRequest2();
         String rootURL = currentRequest.getContextPath();
         Icon iconMetadata = tryGetIcon(iconGuess);
 
diff --git a/core/src/main/java/hudson/LocalPluginManager.java b/core/src/main/java/hudson/LocalPluginManager.java
index d1fcfd678e3a..7ee8c68b40d3 100644
--- a/core/src/main/java/hudson/LocalPluginManager.java
+++ b/core/src/main/java/hudson/LocalPluginManager.java
@@ -26,11 +26,12 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
+import io.jenkins.servlet.ServletContextWrapper;
+import jakarta.servlet.ServletContext;
 import java.io.File;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 
@@ -49,12 +50,20 @@ public LocalPluginManager(@CheckForNull ServletContext context, @NonNull File ro
         super(context, new File(rootDir, "plugins"));
     }
 
+    /**
+     * @deprecated use {@link #LocalPluginManager(ServletContext, File)}
+     */
+    @Deprecated
+    public LocalPluginManager(@CheckForNull javax.servlet.ServletContext context, @NonNull File rootDir) {
+        this(context != null ? ServletContextWrapper.toJakartaServletContext(context) : null, rootDir);
+    }
+
     /**
      * Creates a new LocalPluginManager
      * @param jenkins Jenkins instance that will use the plugin manager.
      */
     public LocalPluginManager(@NonNull Jenkins jenkins) {
-        this(jenkins.servletContext, jenkins.getRootDir());
+        this(jenkins.getServletContext(), jenkins.getRootDir());
     }
 
     /**
@@ -62,7 +71,7 @@ public LocalPluginManager(@NonNull Jenkins jenkins) {
      * @param rootDir Jenkins home directory.
      */
     public LocalPluginManager(@NonNull File rootDir) {
-        this(null, rootDir);
+        this((ServletContext) null, rootDir);
     }
 
     @Override
diff --git a/core/src/main/java/hudson/Plugin.java b/core/src/main/java/hudson/Plugin.java
index c87a2cbe9b3c..1427da9fda8a 100644
--- a/core/src/main/java/hudson/Plugin.java
+++ b/core/src/main/java/hudson/Plugin.java
@@ -33,25 +33,29 @@
 import hudson.model.Saveable;
 import hudson.model.listeners.ItemListener;
 import hudson.model.listeners.SaveableListener;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.GlobalConfiguration;
 import jenkins.model.Jenkins;
 import jenkins.model.Loadable;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Base class of Hudson plugin.
@@ -92,11 +96,11 @@ public abstract class Plugin implements Loadable, Saveable, StaplerProxy {
     /**
      * You do not need to create custom subtypes:
      * <ul>
-     * <li>{@code config.jelly}, {@link #configure(StaplerRequest, JSONObject)}, {@link #load}, and {@link #save}
+     * <li>{@code config.jelly}, {@link #configure(StaplerRequest2, JSONObject)}, {@link #load}, and {@link #save}
      *      can be replaced by {@link GlobalConfiguration}
      * <li>{@link #start} and {@link #postInitialize} can be replaced by {@link Initializer} (or {@link ItemListener#onLoaded})
      * <li>{@link #stop} can be replaced by {@link Terminator}
-     * <li>{@link #setServletContext} can be replaced by {@link Jenkins#servletContext}
+     * <li>{@link #setServletContext} can be replaced by {@link Jenkins#getServletContext}
      * </ul>
      * Note that every plugin gets a {@link DummyImpl} by default,
      * which will still route the URL space, serve {@link #getWrapper}, and so on.
@@ -189,10 +193,10 @@ public void stop() throws Exception {
 
     /**
      * @since 1.233
-     * @deprecated as of 1.305 override {@link #configure(StaplerRequest,JSONObject)} instead
+     * @deprecated as of 1.305 override {@link #configure(StaplerRequest2,JSONObject)} instead
      */
     @Deprecated
-    public void configure(JSONObject formData) throws IOException, ServletException, FormException {
+    public void configure(JSONObject formData) throws IOException, javax.servlet.ServletException, FormException {
     }
 
     /**
@@ -220,16 +224,60 @@ public void configure(JSONObject formData) throws IOException, ServletException,
      * <p>
      * If you are using this method, you'll likely be interested in
      * using {@link #save()} and {@link #load()}.
+     * @since TODO
+     */
+    public void configure(StaplerRequest2 req, JSONObject formData) throws IOException, ServletException, FormException {
+        try {
+            if (Util.isOverridden(Plugin.class, getClass(), "configure", StaplerRequest.class, JSONObject.class)) {
+                configure(StaplerRequest.fromStaplerRequest2(req), formData);
+            } else {
+                configure(formData);
+            }
+        } catch (javax.servlet.ServletException e) {
+            throw ServletExceptionWrapper.toJakartaServletException(e);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #configure(StaplerRequest2, JSONObject)}
      * @since 1.305
      */
-    public void configure(StaplerRequest req, JSONObject formData) throws IOException, ServletException, FormException {
+    @Deprecated
+    public void configure(StaplerRequest req, JSONObject formData) throws IOException, javax.servlet.ServletException, FormException {
         configure(formData);
     }
 
     /**
      * This method serves static resources in the plugin under {@code hudson/plugin/SHORTNAME}.
+     *
+     * @since TODO
+     */
+    public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Plugin.class, getClass(), "doDynamic", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doDynamic(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doDynamicImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doDynamic(StaplerRequest2, StaplerResponse2)}
      */
-    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doDynamicImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doDynamicImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String path = req.getRestOfPath();
 
         String pathUC = path.toUpperCase(Locale.ENGLISH);
diff --git a/core/src/main/java/hudson/PluginManager.java b/core/src/main/java/hudson/PluginManager.java
index 16c22e9ca90c..e1f5d4cc1184 100644
--- a/core/src/main/java/hudson/PluginManager.java
+++ b/core/src/main/java/hudson/PluginManager.java
@@ -66,6 +66,10 @@
 import hudson.util.Service;
 import hudson.util.VersionNumber;
 import hudson.util.XStream2;
+import io.jenkins.servlet.ServletContextWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FilenameFilter;
@@ -118,8 +122,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
 import javax.xml.XMLConstants;
 import javax.xml.parsers.ParserConfigurationException;
 import javax.xml.parsers.SAXParserFactory;
@@ -134,6 +136,7 @@
 import jenkins.model.Jenkins;
 import jenkins.plugins.DetachedPluginsUtil;
 import jenkins.security.CustomClassFilter;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import jenkins.util.io.OnMaster;
 import jenkins.util.xml.RestrictiveEntityResolver;
@@ -143,8 +146,8 @@
 import org.apache.commons.fileupload2.core.DiskFileItemFactory;
 import org.apache.commons.fileupload2.core.FileItem;
 import org.apache.commons.fileupload2.core.FileUploadException;
-import org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload;
-import org.apache.commons.fileupload2.javax.JavaxServletFileUpload;
+import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletDiskFileUpload;
+import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
@@ -165,7 +168,8 @@
 import org.kohsuke.stapler.StaplerOverridable;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -237,11 +241,22 @@ PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
                 return klass.getConstructor(Jenkins.class).newInstance(jenkins);
             }
         },
+        SC_FILE2 {
+            @Override
+            @NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
+                                            @NonNull Jenkins jenkins) throws ReflectiveOperationException {
+                return klass.getConstructor(ServletContext.class, File.class).newInstance(jenkins.getServletContext(), jenkins.getRootDir());
+            }
+        },
+        /**
+         * @deprecated use {@link #SC_FILE2}
+         */
+        @Deprecated
         SC_FILE {
             @Override
             @NonNull PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
                                             @NonNull Jenkins jenkins) throws ReflectiveOperationException {
-                return klass.getConstructor(ServletContext.class, File.class).newInstance(jenkins.servletContext, jenkins.getRootDir());
+                return klass.getConstructor(javax.servlet.ServletContext.class, File.class).newInstance(jenkins.servletContext, jenkins.getRootDir());
             }
         },
         FILE {
@@ -363,6 +378,9 @@ PluginManager doCreate(@NonNull Class<? extends PluginManager> klass,
      */
     private final PluginStrategy strategy;
 
+    /**
+     * @since TODO
+     */
     protected PluginManager(ServletContext context, File rootDir) {
         this.context = context;
 
@@ -378,6 +396,14 @@ protected PluginManager(ServletContext context, File rootDir) {
         strategy = createPluginStrategy();
     }
 
+    /**
+     * @deprecated use {@link #PluginManager(ServletContext, File)}
+     */
+    @Deprecated
+    protected PluginManager(javax.servlet.ServletContext context, File rootDir) {
+        this(context != null ? ServletContextWrapper.toJakartaServletContext(context) : null, rootDir);
+    }
+
     public Api getApi() {
         Jenkins.get().checkPermission(Jenkins.SYSTEM_READ);
         return new Api(this);
@@ -655,7 +681,7 @@ void considerDetachedPlugin(String shortName, String source) {
     protected @NonNull Set<String> loadPluginsFromWar(@NonNull String fromPath, @CheckForNull FilenameFilter filter) {
         Set<String> names = new HashSet<>();
 
-        ServletContext context = Jenkins.get().servletContext;
+        ServletContext context = Jenkins.get().getServletContext();
         Set<String> plugins = Util.fixNull(context.getResourcePaths(fromPath));
         Set<URL> copiedPlugins = new HashSet<>();
         Set<URL> dependencies = new HashSet<>();
@@ -723,7 +749,7 @@ protected static void addDependencies(URL hpiResUrl, String fromPath, Set<URL> d
         String dependencySpec = manifest.getMainAttributes().getValue("Plugin-Dependencies");
         if (dependencySpec != null) {
             String[] dependencyTokens = dependencySpec.split(",");
-            ServletContext context = Jenkins.get().servletContext;
+            ServletContext context = Jenkins.get().getServletContext();
 
             for (String dependencyToken : dependencyTokens) {
                 if (dependencyToken.endsWith(";resolution:=optional")) {
@@ -1597,7 +1623,7 @@ public HttpResponse doPlugins() {
     }
 
     @RequirePOST
-    public HttpResponse doUpdateSources(StaplerRequest req) throws IOException {
+    public HttpResponse doUpdateSources(StaplerRequest2 req) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         if (req.hasParameter("remove")) {
@@ -1632,7 +1658,7 @@ public void doInstallPluginsDone() {
      * Performs the installation of the plugins.
      */
     @RequirePOST
-    public void doInstall(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doInstall(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         Set<String> plugins = new LinkedHashSet<>();
 
@@ -1656,12 +1682,12 @@ public void doInstall(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
      * @param req The request object.
      * @return A JSON response that includes a "correlationId" in the "data" element.
      * That "correlationId" can then be used in calls to
-     * {@link UpdateCenter#doInstallStatus(org.kohsuke.stapler.StaplerRequest)}.
+     * {@link UpdateCenter#doInstallStatus(org.kohsuke.stapler.StaplerRequest2)}.
      * @throws IOException Error reading JSON payload fro request.
      */
     @RequirePOST
     @Restricted(DoNotUse.class) // WebOnly
-    public HttpResponse doInstallPlugins(StaplerRequest req) throws IOException {
+    public HttpResponse doInstallPlugins(StaplerRequest2 req) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         String payload = IOUtils.toString(req.getInputStream(), req.getCharacterEncoding());
         JSONObject request = JSONObject.fromObject(payload);
@@ -1815,7 +1841,7 @@ public HttpResponse doSiteConfigure(@QueryParameter String site) throws IOExcept
     }
 
     @POST
-    public HttpResponse doProxyConfigure(StaplerRequest req) throws IOException, ServletException {
+    public HttpResponse doProxyConfigure(StaplerRequest2 req) throws IOException, ServletException {
         Jenkins jenkins = Jenkins.get();
         jenkins.checkPermission(Jenkins.ADMINISTER);
 
@@ -1880,14 +1906,39 @@ public void cleanup() {
      * Uploads a plugin.
      */
     @RequirePOST
-    public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, ServletException {
+    public HttpResponse doUploadPlugin(StaplerRequest2 req) throws IOException, ServletException {
+        if (Util.isOverridden(PluginManager.class, getClass(), "doUploadPlugin", StaplerRequest.class)) {
+            try {
+                return doUploadPlugin(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            return doUploadPluginImpl(req);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doUploadPlugin(StaplerRequest2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, javax.servlet.ServletException {
+        try {
+            return doUploadPluginImpl(StaplerRequest.toStaplerRequest2(req));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private HttpResponse doUploadPluginImpl(StaplerRequest2 req) throws IOException, ServletException {
         try {
             Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
             String fileName = "";
             PluginCopier copier;
             File tmpDir = Files.createTempDirectory("uploadDir").toFile();
-            JavaxServletFileUpload<DiskFileItem, DiskFileItemFactory> upload = new JavaxServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get());
+            JakartaServletFileUpload<DiskFileItem, DiskFileItemFactory> upload = new JakartaServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get());
             List<DiskFileItem> items = upload.parseRequest(req);
             String string = items.get(1).getString();
             if (string != null && !string.isBlank()) {
@@ -1965,7 +2016,7 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl
     }
 
     @Restricted(NoExternalUse.class)
-    @RequirePOST public FormValidation doCheckPluginUrl(StaplerRequest request, @QueryParameter String value) throws IOException {
+    @RequirePOST public FormValidation doCheckPluginUrl(StaplerRequest2 request, @QueryParameter String value) throws IOException {
         if (value != null && !value.isBlank()) {
             try {
                 URL url = new URL(value);
@@ -1984,7 +2035,7 @@ public HttpResponse doUploadPlugin(StaplerRequest req) throws IOException, Servl
     }
 
     @Restricted(NoExternalUse.class)
-    @RequirePOST public FormValidation doCheckUpdateSiteUrl(StaplerRequest request, @QueryParameter String value) throws InterruptedException {
+    @RequirePOST public FormValidation doCheckUpdateSiteUrl(StaplerRequest2 request, @QueryParameter String value) throws InterruptedException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         return checkUpdateSiteURL(value);
     }
@@ -2217,7 +2268,7 @@ private void logPluginWarnings(Map.Entry<String, VersionNumber> requestedPlugin,
     }
 
     /**
-     * Like {@link #doInstallNecessaryPlugins(StaplerRequest)} but only checks if everything is installed
+     * Like {@link #doInstallNecessaryPlugins(StaplerRequest2)} but only checks if everything is installed
      * or if some plugins need updates or installation.
      *
      * This method runs without side-effect. I'm still requiring the ADMINISTER permission since
@@ -2227,7 +2278,7 @@ private void logPluginWarnings(Map.Entry<String, VersionNumber> requestedPlugin,
      * @since 1.483
      */
     @RequirePOST
-    public JSONArray doPrevalidateConfig(StaplerRequest req) throws IOException {
+    public JSONArray doPrevalidateConfig(StaplerRequest2 req) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         JSONArray response = new JSONArray();
@@ -2252,7 +2303,7 @@ public JSONArray doPrevalidateConfig(StaplerRequest req) throws IOException {
      * @since 1.483
      */
     @RequirePOST
-    public HttpResponse doInstallNecessaryPlugins(StaplerRequest req) throws IOException {
+    public HttpResponse doInstallNecessaryPlugins(StaplerRequest2 req) throws IOException {
         prevalidateConfig(req.getInputStream());
         return HttpResponses.redirectViaContextPath("pluginManager/updates/");
     }
diff --git a/core/src/main/java/hudson/PluginWrapper.java b/core/src/main/java/hudson/PluginWrapper.java
index 47cfcb02d955..c8cd9f5240a0 100644
--- a/core/src/main/java/hudson/PluginWrapper.java
+++ b/core/src/main/java/hudson/PluginWrapper.java
@@ -80,8 +80,8 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -1212,7 +1212,7 @@ public PluginWrapper getPlugin(String shortName) {
         /**
          * Depending on whether the user said "dismiss" or "correct", send him to the right place.
          */
-        public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             if (req.hasParameter("correct")) {
                 rsp.sendRedirect(req.getContextPath() + "/pluginManager");
 
diff --git a/core/src/main/java/hudson/ProxyConfigurationManager.java b/core/src/main/java/hudson/ProxyConfigurationManager.java
index 52f15f84c87e..d3ae0d79ee0e 100644
--- a/core/src/main/java/hudson/ProxyConfigurationManager.java
+++ b/core/src/main/java/hudson/ProxyConfigurationManager.java
@@ -32,7 +32,7 @@
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @Extension @Restricted(NoExternalUse.class)
 public class ProxyConfigurationManager extends GlobalConfiguration {
@@ -48,7 +48,7 @@ public Descriptor<ProxyConfiguration> getProxyDescriptor() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         ProxyConfiguration pc = req.bindJSON(ProxyConfiguration.class, json);
         try {
             saveProxyConfiguration(pc);
diff --git a/core/src/main/java/hudson/ResponseHeaderFilter.java b/core/src/main/java/hudson/ResponseHeaderFilter.java
index 90fb0be87d37..416e5c4c6919 100644
--- a/core/src/main/java/hudson/ResponseHeaderFilter.java
+++ b/core/src/main/java/hudson/ResponseHeaderFilter.java
@@ -24,15 +24,15 @@
 
 package hudson;
 
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Enumeration;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * This filter allows you to modify headers set by the container or other servlets
@@ -77,7 +77,7 @@
  *
  * @author Mike Wille
  */
-public class ResponseHeaderFilter implements Filter {
+public class ResponseHeaderFilter implements CompatibleFilter {
     private FilterConfig config;
 
     @Override
diff --git a/core/src/main/java/hudson/Util.java b/core/src/main/java/hudson/Util.java
index abe9f97d6551..5ca66e9c4424 100644
--- a/core/src/main/java/hudson/Util.java
+++ b/core/src/main/java/hudson/Util.java
@@ -125,6 +125,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Various utility methods that don't have more proper home.
@@ -1850,9 +1851,11 @@ public static long daysElapsedSince(@NonNull Date date) {
     /**
      * Find the specific ancestor, or throw an exception.
      * Useful for an ancestor we know is inside the URL to ease readability
+     *
+     * @since TODO
      */
     @Restricted(NoExternalUse.class)
-    public static @NonNull <T> T getNearestAncestorOfTypeOrThrow(@NonNull StaplerRequest request, @NonNull Class<T> clazz) {
+    public static @NonNull <T> T getNearestAncestorOfTypeOrThrow(@NonNull StaplerRequest2 request, @NonNull Class<T> clazz) {
         T t = request.findAncestorObject(clazz);
         if (t == null) {
             throw new IllegalArgumentException("No ancestor of type " + clazz.getName() + " in the request");
@@ -1860,6 +1863,15 @@ public static long daysElapsedSince(@NonNull Date date) {
         return t;
     }
 
+    /**
+     * @deprecated use {@link #getNearestAncestorOfTypeOrThrow(StaplerRequest2, Class)}
+     */
+    @Deprecated
+    @Restricted(NoExternalUse.class)
+    public static @NonNull <T> T getNearestAncestorOfTypeOrThrow(@NonNull StaplerRequest request, @NonNull Class<T> clazz) {
+        return getNearestAncestorOfTypeOrThrow(StaplerRequest.toStaplerRequest2(request), clazz);
+    }
+
     @Restricted(NoExternalUse.class)
     public static void printRedirect(String contextPath, String redirectUrl, String message, PrintWriter out) {
         out.printf(
diff --git a/core/src/main/java/hudson/WebAppMain.java b/core/src/main/java/hudson/WebAppMain.java
index 9f328328c710..986452797f90 100644
--- a/core/src/main/java/hudson/WebAppMain.java
+++ b/core/src/main/java/hudson/WebAppMain.java
@@ -45,6 +45,12 @@
 import hudson.util.NoHomeDir;
 import hudson.util.NoTempDir;
 import hudson.util.RingBufferLogHandler;
+import io.jenkins.servlet.ServletContextEventWrapper;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextListener;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.SessionTrackingMode;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -65,11 +71,6 @@
 import java.util.logging.Level;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
-import javax.servlet.ServletResponse;
-import javax.servlet.SessionTrackingMode;
 import jenkins.model.Jenkins;
 import jenkins.util.JenkinsJVM;
 import jenkins.util.SystemProperties;
@@ -320,10 +321,21 @@ private void recordBootAttempt(File home) {
         }
     }
 
+    /**
+     * @since TODO
+     */
     public static void installExpressionFactory(ServletContextEvent event) {
         JellyFacet.setExpressionFactory(event, new ExpressionFactory2());
     }
 
+    /**
+     * @deprecated use {@link #installExpressionFactory(ServletContextEvent)}
+     */
+    @Deprecated
+    public static void installExpressionFactory(javax.servlet.ServletContextEvent event) {
+        installExpressionFactory(ServletContextEventWrapper.toJakartaServletContextEvent(event));
+    }
+
     /**
      * Installs log handler to monitor all Hudson logs.
      */
diff --git a/core/src/main/java/hudson/cli/CLIAction.java b/core/src/main/java/hudson/cli/CLIAction.java
index 9e29b141560c..a2fc5f590197 100644
--- a/core/src/main/java/hudson/cli/CLIAction.java
+++ b/core/src/main/java/hudson/cli/CLIAction.java
@@ -26,6 +26,8 @@
 
 import hudson.Extension;
 import hudson.model.UnprotectedRootAction;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.IOException;
@@ -45,8 +47,6 @@
 import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.util.FullDuplexHttpService;
 import jenkins.util.SystemProperties;
@@ -59,8 +59,8 @@
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.core.Authentication;
 
 /**
@@ -97,7 +97,7 @@ public String getUrlName() {
         return "cli";
     }
 
-    public void doCommand(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    public void doCommand(StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         final Jenkins jenkins = Jenkins.get();
         jenkins.checkPermission(Jenkins.READ);
 
@@ -121,7 +121,7 @@ public boolean isWebSocketSupported() {
     /**
      * WebSocket endpoint.
      */
-    public HttpResponse doWs(StaplerRequest req) {
+    public HttpResponse doWs(StaplerRequest2 req) {
         if (!WebSockets.isSupported()) {
             return HttpResponses.notFound();
         }
@@ -216,7 +216,7 @@ protected void closed(int statusCode, String reason) {
 
     @Override
     public Object getTarget() {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req.getRestOfPath().isEmpty() && "POST".equals(req.getMethod())) {
             // CLI connection request
             if ("false".equals(req.getParameter("remoting"))) {
@@ -349,7 +349,7 @@ private class PlainCliEndpointResponse extends FullDuplexHttpService.Response {
         }
 
         @Override
-        protected FullDuplexHttpService createService(StaplerRequest req, UUID uuid) throws IOException {
+        protected FullDuplexHttpService createService(StaplerRequest2 req, UUID uuid) throws IOException {
             return new FullDuplexHttpService(uuid) {
                 @Override
                 protected void run(InputStream upload, OutputStream download) throws IOException, InterruptedException {
diff --git a/core/src/main/java/hudson/cli/CliCrumbExclusion.java b/core/src/main/java/hudson/cli/CliCrumbExclusion.java
index 4e3064f43178..08c204eb55b1 100644
--- a/core/src/main/java/hudson/cli/CliCrumbExclusion.java
+++ b/core/src/main/java/hudson/cli/CliCrumbExclusion.java
@@ -26,11 +26,11 @@
 
 import hudson.Extension;
 import hudson.security.csrf.CrumbExclusion;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
 
diff --git a/core/src/main/java/hudson/cli/ReloadConfigurationCommand.java b/core/src/main/java/hudson/cli/ReloadConfigurationCommand.java
index 6b29dcf52904..aab260747f65 100644
--- a/core/src/main/java/hudson/cli/ReloadConfigurationCommand.java
+++ b/core/src/main/java/hudson/cli/ReloadConfigurationCommand.java
@@ -50,7 +50,7 @@ protected int run() throws Exception {
         // Or perhaps simpler to inline the thread body of doReload?
         j.doReload();
         Object app;
-        while ((app = WebApp.get(j.servletContext).getApp()) instanceof HudsonIsLoading) {
+        while ((app = WebApp.get(j.getServletContext()).getApp()) instanceof HudsonIsLoading) {
             Thread.sleep(100);
         }
         if (app instanceof Jenkins) {
diff --git a/core/src/main/java/hudson/cli/UpdateNodeCommand.java b/core/src/main/java/hudson/cli/UpdateNodeCommand.java
index c9210f89cc68..5909a2f0fcf2 100644
--- a/core/src/main/java/hudson/cli/UpdateNodeCommand.java
+++ b/core/src/main/java/hudson/cli/UpdateNodeCommand.java
@@ -26,8 +26,8 @@
 
 import hudson.Extension;
 import hudson.model.Node;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.kohsuke.args4j.Argument;
 
 /**
diff --git a/core/src/main/java/hudson/console/AnnotatedLargeText.java b/core/src/main/java/hudson/console/AnnotatedLargeText.java
index 4e0d3b9908af..1798512f3e03 100644
--- a/core/src/main/java/hudson/console/AnnotatedLargeText.java
+++ b/core/src/main/java/hudson/console/AnnotatedLargeText.java
@@ -30,6 +30,7 @@
 
 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import hudson.Util;
 import hudson.remoting.ObjectInputStreamEx;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
@@ -50,10 +51,13 @@
 import javax.crypto.CipherOutputStream;
 import jenkins.model.Jenkins;
 import jenkins.security.CryptoConfidentialKey;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import org.jenkinsci.remoting.util.AnonymousClassWarnings;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.framework.io.ByteBuffer;
 import org.kohsuke.stapler.framework.io.LargeText;
 
@@ -90,14 +94,44 @@ public AnnotatedLargeText(ByteBuffer memory, Charset charset, boolean completed,
         this.context = context;
     }
 
+    /**
+     * @since TODO
+     */
+    public void doProgressiveHtml(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
+        if (Util.isOverridden(AnnotatedLargeText.class, getClass(), "doProgressiveHtml", StaplerRequest.class, StaplerResponse.class)) {
+            doProgressiveHtml(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            doProgressiveHtmlImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doProgressiveHtml(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
     public void doProgressiveHtml(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        doProgressiveHtmlImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doProgressiveHtmlImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         req.setAttribute("html", true);
         doProgressText(req, rsp);
     }
 
     /**
      * Aliasing what I think was a wrong name in {@link LargeText}
+     *
+     * @since TODO
      */
+    public void doProgressiveText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
+        doProgressText(req, rsp);
+    }
+
+    /**
+     * @deprecated use {@link #doProgressiveText(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     public void doProgressiveText(StaplerRequest req, StaplerResponse rsp) throws IOException {
         doProgressText(req, rsp);
     }
@@ -107,16 +141,35 @@ public void doProgressiveText(StaplerRequest req, StaplerResponse rsp) throws IO
      * and use this request attribute to differentiate.
      */
     private boolean isHtml() {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         return req != null && req.getAttribute("html") != null;
     }
 
+    /**
+     * @since TODO
+     */
     @Override
+    protected void setContentType(StaplerResponse2 rsp) {
+        if (Util.isOverridden(AnnotatedLargeText.class, getClass(), "setContentType", StaplerResponse.class)) {
+            setContentType(StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            setContentTypeImpl(rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #setContentType(StaplerResponse2)}
+     */
+    @Deprecated
     protected void setContentType(StaplerResponse rsp) {
+        setContentTypeImpl(StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void setContentTypeImpl(StaplerResponse2 rsp) {
         rsp.setContentType(isHtml() ? "text/html;charset=UTF-8" : "text/plain;charset=UTF-8");
     }
 
-    private ConsoleAnnotator<T> createAnnotator(StaplerRequest req) throws IOException {
+    private ConsoleAnnotator<T> createAnnotator(StaplerRequest2 req) throws IOException {
         try {
             String base64 = req != null ? req.getHeader("X-ConsoleAnnotator") : null;
             if (base64 != null) {
@@ -176,7 +229,7 @@ public long writeRawLogTo(long start, OutputStream out) throws IOException {
     @CheckReturnValue
     public long writeHtmlTo(long start, Writer w) throws IOException {
         ConsoleAnnotationOutputStream<T> caw = new ConsoleAnnotationOutputStream<>(
-                w, createAnnotator(Stapler.getCurrentRequest()), context, charset);
+                w, createAnnotator(Stapler.getCurrentRequest2()), context, charset);
         long r = super.writeLogTo(start, caw);
 
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -185,7 +238,7 @@ public long writeHtmlTo(long start, Writer w) throws IOException {
         oos.writeLong(System.currentTimeMillis()); // send timestamp to prevent a replay attack
         oos.writeObject(caw.getConsoleAnnotator());
         oos.close();
-        StaplerResponse rsp = Stapler.getCurrentResponse();
+        StaplerResponse2 rsp = Stapler.getCurrentResponse2();
         if (rsp != null)
             rsp.setHeader("X-ConsoleAnnotator", Base64.getEncoder().encodeToString(baos.toByteArray()));
         return r;
diff --git a/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java b/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java
index bb68ccc66194..e63e2dab5cae 100644
--- a/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java
+++ b/core/src/main/java/hudson/console/ConsoleAnnotationDescriptor.java
@@ -28,13 +28,13 @@
 import hudson.DescriptorExtensionList;
 import hudson.ExtensionPoint;
 import hudson.model.Descriptor;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.net.URL;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 
 /**
@@ -81,12 +81,12 @@ private URL hasResource(String name) {
     }
 
     @WebMethod(name = "script.js")
-    public void doScriptJs(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScriptJs(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.serveFile(req, hasResource("/script.js"), TimeUnit.DAYS.toMillis(1));
     }
 
     @WebMethod(name = "style.css")
-    public void doStyleCss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doStyleCss(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.serveFile(req, hasResource("/style.css"), TimeUnit.DAYS.toMillis(1));
     }
 
diff --git a/core/src/main/java/hudson/console/ConsoleAnnotatorFactory.java b/core/src/main/java/hudson/console/ConsoleAnnotatorFactory.java
index b2f6948fd155..3e56f80ed5d0 100644
--- a/core/src/main/java/hudson/console/ConsoleAnnotatorFactory.java
+++ b/core/src/main/java/hudson/console/ConsoleAnnotatorFactory.java
@@ -28,15 +28,15 @@
 import hudson.ExtensionList;
 import hudson.ExtensionPoint;
 import hudson.model.Run;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.net.URL;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
 import org.jvnet.tiger_types.Types;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 
 /**
@@ -113,12 +113,12 @@ private URL getResource(String fileName) {
      * Serves the JavaScript file associated with this console annotator factory.
      */
     @WebMethod(name = "script.js")
-    public void doScriptJs(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScriptJs(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.serveFile(req, getResource("/script.js"), TimeUnit.DAYS.toMillis(1));
     }
 
     @WebMethod(name = "style.css")
-    public void doStyleCss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doStyleCss(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.serveFile(req, getResource("/style.css"), TimeUnit.DAYS.toMillis(1));
     }
 
diff --git a/core/src/main/java/hudson/console/HyperlinkNote.java b/core/src/main/java/hudson/console/HyperlinkNote.java
index 1e582dab2b4a..8aa011660592 100644
--- a/core/src/main/java/hudson/console/HyperlinkNote.java
+++ b/core/src/main/java/hudson/console/HyperlinkNote.java
@@ -37,7 +37,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Turns a text into a hyperlink by specifying the URL separately.
@@ -62,7 +62,7 @@ public HyperlinkNote(String url, int length) {
     public ConsoleAnnotator annotate(Object context, MarkupText text, int charPos) {
         String url = this.url;
         if (url.startsWith("/")) {
-            StaplerRequest req = Stapler.getCurrentRequest();
+            StaplerRequest2 req = Stapler.getCurrentRequest2();
             if (req != null) {
                 // if we are serving HTTP request, we want to use app relative URL
                 url = req.getContextPath() + url;
diff --git a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java
index e2bfa4678fc9..425c52150949 100644
--- a/core/src/main/java/hudson/diagnosis/OldDataMonitor.java
+++ b/core/src/main/java/hudson/diagnosis/OldDataMonitor.java
@@ -65,8 +65,8 @@
 import org.kohsuke.stapler.HttpRedirect;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -310,7 +310,7 @@ public Iterator<VersionNumber> getVersionList() {
      * Depending on whether the user said "yes" or "no", send him to the right place.
      */
     @RequirePOST
-    public HttpResponse doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public HttpResponse doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.hasParameter("no")) {
             disable(true);
             return HttpResponses.redirectViaContextPath("/manage");
@@ -324,7 +324,7 @@ public HttpResponse doAct(StaplerRequest req, StaplerResponse rsp) throws IOExce
      * Remove those items from the data map.
      */
     @RequirePOST
-    public HttpResponse doUpgrade(StaplerRequest req, StaplerResponse rsp) {
+    public HttpResponse doUpgrade(StaplerRequest2 req, StaplerResponse2 rsp) {
         final String thruVerParam = req.getParameter("thruVer");
         final VersionNumber thruVer = thruVerParam.equals("all") ? null : new VersionNumber(thruVerParam);
 
@@ -341,7 +341,7 @@ public HttpResponse doUpgrade(StaplerRequest req, StaplerResponse rsp) {
      * Remove those items from the data map.
      */
     @RequirePOST
-    public HttpResponse doDiscard(StaplerRequest req, StaplerResponse rsp) {
+    public HttpResponse doDiscard(StaplerRequest2 req, StaplerResponse2 rsp) {
         saveAndRemoveEntries(entry -> entry.getValue().max == null);
 
         return HttpResponses.forwardToPreviousPage();
@@ -377,7 +377,7 @@ private void saveAndRemoveEntries(Predicate<Map.Entry<SaveableReference, Version
         data.keySet().removeAll(removed);
     }
 
-    public HttpResponse doIndex(StaplerResponse rsp) throws IOException {
+    public HttpResponse doIndex(StaplerResponse2 rsp) throws IOException {
         return new HttpRedirect("manage");
     }
 
diff --git a/core/src/main/java/hudson/diagnosis/ReverseProxySetupMonitor.java b/core/src/main/java/hudson/diagnosis/ReverseProxySetupMonitor.java
index af7b2579db74..374df6da783e 100644
--- a/core/src/main/java/hudson/diagnosis/ReverseProxySetupMonitor.java
+++ b/core/src/main/java/hudson/diagnosis/ReverseProxySetupMonitor.java
@@ -41,7 +41,7 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -68,7 +68,7 @@ public boolean isActivated() {
 
     @Restricted(DoNotUse.class) // WebOnly
     @RestrictedSince("2.235")
-    public HttpResponse doTest(StaplerRequest request, @QueryParameter boolean testWithContext) {
+    public HttpResponse doTest(StaplerRequest2 request, @QueryParameter boolean testWithContext) {
         String referer = request.getReferer();
         Jenkins j = Jenkins.get();
         String redirect;
diff --git a/core/src/main/java/hudson/diagnosis/TooManyJobsButNoView.java b/core/src/main/java/hudson/diagnosis/TooManyJobsButNoView.java
index 6412ac63bcb2..1ea6c6336a02 100644
--- a/core/src/main/java/hudson/diagnosis/TooManyJobsButNoView.java
+++ b/core/src/main/java/hudson/diagnosis/TooManyJobsButNoView.java
@@ -30,8 +30,8 @@
 import java.io.IOException;
 import jenkins.model.Jenkins;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -64,7 +64,7 @@ public boolean isActivated() {
      * Depending on whether the user said "yes" or "no", send him to the right place.
      */
     @RequirePOST
-    public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         if (req.hasParameter("no")) {
             disable(true);
diff --git a/core/src/main/java/hudson/init/impl/GroovyInitScript.java b/core/src/main/java/hudson/init/impl/GroovyInitScript.java
index 17f6a4702c94..ffe8c77513c8 100644
--- a/core/src/main/java/hudson/init/impl/GroovyInitScript.java
+++ b/core/src/main/java/hudson/init/impl/GroovyInitScript.java
@@ -39,6 +39,6 @@
 public class GroovyInitScript {
     @Initializer(after = JOB_CONFIG_ADAPTED)
     public static void init(Jenkins j) {
-        new GroovyHookScript("init", j.servletContext, j.getRootDir(), j.getPluginManager().uberClassLoader).run();
+        new GroovyHookScript("init", j.getServletContext(), j.getRootDir(), j.getPluginManager().uberClassLoader).run();
     }
 }
diff --git a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java
index c305e9a6febc..4a8d6ce51900 100644
--- a/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java
+++ b/core/src/main/java/hudson/init/impl/InstallUncaughtExceptionHandler.java
@@ -2,22 +2,22 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.init.Initializer;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.EOFException;
 import java.io.IOException;
 import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.kohsuke.MetaInfServices;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.UncaughtExceptionFilter;
 import org.kohsuke.stapler.WebApp;
 
@@ -30,7 +30,7 @@ public class InstallUncaughtExceptionHandler {
 
     @Initializer
     public static void init(final Jenkins j) throws IOException {
-        UncaughtExceptionFilter.setUncaughtExceptionHandler(j.servletContext, (e, context, req, rsp) -> handleException(j, e, req, rsp, 500));
+        UncaughtExceptionFilter.setUncaughtExceptionHandler(j.getServletContext(), (e, context, req, rsp) -> handleException(j, e, req, rsp, 500));
         try {
             Thread.setDefaultUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler());
             LOGGER.log(Level.FINE, "Successfully installed a global UncaughtExceptionHandler.");
@@ -53,10 +53,10 @@ private static void handleException(Jenkins j, Throwable e, HttpServletRequest r
         String id = UUID.randomUUID().toString();
         LOGGER.log(isEOFException(e) ? Level.FINE : Level.WARNING, "Caught unhandled exception with ID " + id, e);
         req.setAttribute("jenkins.exception.id", id);
-        req.setAttribute("javax.servlet.error.exception", e);
+        req.setAttribute("jakarta.servlet.error.exception", e);
         rsp.setStatus(code);
         try {
-            WebApp.get(j.servletContext).getSomeStapler().invoke(req, rsp, j, "/oops");
+            WebApp.get(j.getServletContext()).getSomeStapler().invoke(req, rsp, j, "/oops");
         } catch (ServletException | IOException x) {
             if (!Stapler.isSocketException(x)) {
                 throw x;
@@ -75,7 +75,7 @@ public HttpResponses.HttpResponseException handleError(int code, Throwable cause
             }
             return new HttpResponses.HttpResponseException(cause) {
                 @Override
-                public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+                public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                     handleException(Jenkins.get(), cause, req, rsp, code);
                 }
             };
diff --git a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java
index 875a3e4ef7e0..c54a90d1c576 100644
--- a/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java
+++ b/core/src/main/java/hudson/lifecycle/WindowsInstallerLink.java
@@ -35,6 +35,7 @@
 import hudson.model.TaskListener;
 import hudson.util.StreamTaskListener;
 import hudson.util.jna.DotNet;
+import jakarta.servlet.ServletException;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -43,7 +44,6 @@
 import java.nio.file.Files;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import org.apache.commons.io.FileUtils;
@@ -52,8 +52,8 @@
 import org.apache.tools.ant.taskdefs.Move;
 import org.apache.tools.ant.types.FileSet;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -116,7 +116,7 @@ public boolean isInstalled() {
      * Performs installation.
      */
     @RequirePOST
-    public void doDoInstall(StaplerRequest req, StaplerResponse rsp, @QueryParameter("dir") String _dir) throws IOException, ServletException {
+    public void doDoInstall(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter("dir") String _dir) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         if (installationDir != null) {
@@ -168,7 +168,7 @@ public void doDoInstall(StaplerRequest req, StaplerResponse rsp, @QueryParameter
     /**
      * Copies a single resource into the target folder, by the given name, and handle errors gracefully.
      */
-    private void copy(StaplerRequest req, StaplerResponse rsp, File dir, URL src, String name) throws ServletException, IOException {
+    private void copy(StaplerRequest2 req, StaplerResponse2 rsp, File dir, URL src, String name) throws ServletException, IOException {
         try {
             FileUtils.copyURLToFile(src, new File(dir, name));
         } catch (IOException e) {
@@ -179,7 +179,7 @@ private void copy(StaplerRequest req, StaplerResponse rsp, File dir, URL src, St
     }
 
     @RequirePOST
-    public void doRestart(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRestart(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         if (installationDir == null) {
@@ -250,11 +250,11 @@ private DefaultLogger createLogger() {
     /**
      * Displays the error in a page.
      */
-    protected final void sendError(Exception e, StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    protected final void sendError(Exception e, StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         sendError(e.getMessage(), req, rsp);
     }
 
-    protected final void sendError(String message, StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    protected final void sendError(String message, StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         req.setAttribute("message", message);
         req.setAttribute("pre", true);
         rsp.forward(Jenkins.get(), "error", req);
diff --git a/core/src/main/java/hudson/logging/LogRecorder.java b/core/src/main/java/hudson/logging/LogRecorder.java
index 86aea6575048..ad4c40028547 100644
--- a/core/src/main/java/hudson/logging/LogRecorder.java
+++ b/core/src/main/java/hudson/logging/LogRecorder.java
@@ -48,6 +48,7 @@
 import hudson.util.HttpResponses;
 import hudson.util.RingBufferLogHandler;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.io.Serializable;
@@ -71,7 +72,6 @@
 import java.util.logging.LogManager;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.Loadable;
 import jenkins.security.MasterToSlaveCallable;
@@ -82,8 +82,8 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
 
@@ -439,7 +439,7 @@ public LogRecorderManager getParent() {
      * Accepts submission from the configuration page.
      */
     @POST
-    public synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         JSONObject src = req.getSubmittedForm();
@@ -536,7 +536,7 @@ public int hashCode() {
      * Deletes this recorder, then go back to the parent.
      */
     @RequirePOST
-    public synchronized void doDoDelete(StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doDoDelete(StaplerResponse2 rsp) throws IOException, ServletException {
         delete();
         rsp.sendRedirect2("..");
     }
@@ -562,7 +562,7 @@ public void delete() throws IOException {
     /**
      * RSS feed for log entries.
      */
-    public void doRss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRss(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         LogRecorderManager.doRss(req, rsp, getLogRecords());
     }
 
diff --git a/core/src/main/java/hudson/logging/LogRecorderManager.java b/core/src/main/java/hudson/logging/LogRecorderManager.java
index 70856024df12..2c589adaa612 100644
--- a/core/src/main/java/hudson/logging/LogRecorderManager.java
+++ b/core/src/main/java/hudson/logging/LogRecorderManager.java
@@ -38,6 +38,7 @@
 import hudson.model.RSS;
 import hudson.util.CopyOnWriteMap;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
@@ -53,7 +54,6 @@
 import java.util.logging.LogManager;
 import java.util.logging.LogRecord;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.JenkinsLocationConfiguration;
 import jenkins.model.ModelObjectWithChildren;
@@ -68,8 +68,8 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -188,7 +188,7 @@ public FormValidation doCheckNewName(@QueryParameter String name) {
     }
 
     @Override
-    public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ContextMenu menu = new ContextMenu();
         menu.add("all", "All Jenkins Logs");
         for (LogRecorder lr : recorders) {
@@ -225,14 +225,14 @@ public HttpResponse doConfigLogger(@QueryParameter String name, @QueryParameter
     /**
      * RSS feed for log entries.
      */
-    public void doRss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRss(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         doRss(req, rsp, Jenkins.logRecords);
     }
 
     /**
      * Renders the given log recorders as RSS.
      */
-    /*package*/ static void doRss(StaplerRequest req, StaplerResponse rsp, List<LogRecord> logs) throws IOException, ServletException {
+    /*package*/ static void doRss(StaplerRequest2 req, StaplerResponse2 rsp, List<LogRecord> logs) throws IOException, ServletException {
         // filter log records based on the log level
         String entryType = "all";
         String level = req.getParameter("level");
diff --git a/core/src/main/java/hudson/markup/MarkupFormatter.java b/core/src/main/java/hudson/markup/MarkupFormatter.java
index e588e0cfcc8e..a3bf53a739a1 100644
--- a/core/src/main/java/hudson/markup/MarkupFormatter.java
+++ b/core/src/main/java/hudson/markup/MarkupFormatter.java
@@ -28,6 +28,7 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.ExtensionPoint;
 import hudson.model.AbstractDescribableImpl;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -44,7 +45,8 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.verb.GET;
 import org.kohsuke.stapler.verb.POST;
@@ -138,7 +140,7 @@ public HttpResponse doPreviewDescription(@QueryParameter String text) throws IOE
     @GET
     @WebMethod(name = "previewDescription")
     @Restricted(NoExternalUse.class)
-    public HttpResponse previewsNowNeedPostForSecurity2153(@QueryParameter String text, StaplerRequest req) throws IOException {
+    public HttpResponse previewsNowNeedPostForSecurity2153(@QueryParameter String text, StaplerRequest2 req) throws IOException {
         LOGGER.log(Level.FINE, "Received a GET request at " + req.getRequestURL());
         if (PREVIEWS_ALLOW_GET) {
             return doPreviewDescription(text);
@@ -155,15 +157,18 @@ public HttpResponse previewsNowNeedPostForSecurity2153(@QueryParameter String te
      */
     private static HttpResponse html(int status, @NonNull String html, @NonNull Map<String, String> headers) {
         // TODO Move to Stapler's HttpResponses, (also add a corresponding 'text' method)
-        return (req, rsp, node) -> {
-            rsp.setContentType("text/html;charset=UTF-8");
-            rsp.setStatus(status);
-            for (Map.Entry<String, String> header : headers.entrySet()) {
-                rsp.setHeader(header.getKey(), header.getValue());
+        return new HttpResponse() {
+            @Override
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
+                rsp.setContentType("text/html;charset=UTF-8");
+                rsp.setStatus(status);
+                for (Map.Entry<String, String> header : headers.entrySet()) {
+                    rsp.setHeader(header.getKey(), header.getValue());
+                }
+                PrintWriter pw = rsp.getWriter();
+                pw.print(html);
+                pw.flush();
             }
-            PrintWriter pw = rsp.getWriter();
-            pw.print(html);
-            pw.flush();
         };
     }
 }
diff --git a/core/src/main/java/hudson/model/AbstractBuild.java b/core/src/main/java/hudson/model/AbstractBuild.java
index 85d62df78896..d993d722eacb 100644
--- a/core/src/main/java/hudson/model/AbstractBuild.java
+++ b/core/src/main/java/hudson/model/AbstractBuild.java
@@ -62,6 +62,8 @@
 import hudson.util.HttpResponses;
 import hudson.util.Iterators;
 import hudson.util.VariableResolver;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.io.InterruptedIOException;
@@ -81,7 +83,6 @@
 import java.util.TreeSet;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.lazy.BuildReference;
 import jenkins.model.lazy.LazyBuildMixIn;
@@ -275,7 +276,7 @@ public Queue.Executable getParentExecutable() {
      */
     @Deprecated(since = "2.364")
     public String getUpUrl() {
-        return Functions.getNearestAncestorUrl(Stapler.getCurrentRequest(), getParent()) + '/';
+        return Functions.getNearestAncestorUrl(Stapler.getCurrentRequest2(), getParent()) + '/';
     }
 
     /**
@@ -1391,8 +1392,12 @@ public List<AbstractBuild> getBuilds() {
      */
     @Deprecated
     @RequirePOST // #doStop() should be preferred, but better to be safe
-    public void doStop(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
-        doStop().generateResponse(req, rsp, this);
+    public void doStop(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doStop().generateResponse(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), this);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
     /**
diff --git a/core/src/main/java/hudson/model/AbstractItem.java b/core/src/main/java/hudson/model/AbstractItem.java
index adebec8f289f..af64ff19df34 100644
--- a/core/src/main/java/hudson/model/AbstractItem.java
+++ b/core/src/main/java/hudson/model/AbstractItem.java
@@ -25,7 +25,7 @@
 
 package hudson.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
 
 import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -47,6 +47,8 @@
 import hudson.util.FormValidation;
 import hudson.util.IOUtils;
 import hudson.util.Secret;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -59,7 +61,6 @@
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import javax.servlet.ServletException;
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.sax.SAXSource;
@@ -70,6 +71,7 @@
 import jenkins.model.Loadable;
 import jenkins.model.queue.ItemDeletion;
 import jenkins.security.NotReallyRoleSensitiveCallable;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import jenkins.util.xml.XMLUtils;
 import org.apache.tools.ant.Project;
@@ -87,7 +89,9 @@
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -530,7 +534,7 @@ public void onCopiedFrom(Item src) {
     @Override
     public final String getUrl() {
         // try to stick to the current view if possible
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         String shortUrl = getShortUrl();
         String uri = req == null ? null : req.getRequestURI();
         if (req != null) {
@@ -644,9 +648,36 @@ private Object readResolve() {
 
     /**
      * Accepts the new description.
+     *
+     * @since TODO
      */
     @RequirePOST
-    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(AbstractItem.class, getClass(), "doSubmitDescription", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doSubmitDescription(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doSubmitDescriptionImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doSubmitDescription(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doSubmitDescriptionImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doSubmitDescriptionImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         checkPermission(CONFIGURE);
 
         setDescription(req.getParameter("description"));
@@ -658,9 +689,32 @@ public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse
      * Note on the funny name: for reasons of historical compatibility, this URL is {@code /doDelete}
      * since it predates {@code <l:confirmationLink>}. {@code /delete} goes to a Jelly page
      * which should now be unused by core but is left in case plugins are still using it.
+     *
+     * @since TODO
      */
     @RequirePOST
-    public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public void doDoDelete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
+        if (Util.isOverridden(AbstractItem.class, getClass(), "doDoDelete", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doDoDelete(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doDoDeleteImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doDoDelete(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException, InterruptedException {
+        doDoDeleteImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doDoDeleteImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, InterruptedException {
         delete();
         if (req == null || rsp == null) { // CLI
             return;
@@ -681,8 +735,28 @@ public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOExcepti
         rsp.sendRedirect2(req.getContextPath() + '/' + url);
     }
 
+    /**
+     * @since TODO
+     */
     @Override
-    public void delete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void delete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        deleteImpl(rsp);
+    }
+
+    /**
+     * @deprecated use {@link #delete(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @Override
+    public void delete(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            deleteImpl(StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void deleteImpl(StaplerResponse2 rsp) throws IOException, ServletException {
         try {
             delete();
             rsp.setStatus(204);
@@ -755,10 +829,31 @@ protected void performDelete() throws IOException, InterruptedException {
 
     /**
      * Accepts {@code config.xml} submission, as well as serve it.
+     *
+     * @since TODO
      */
     @WebMethod(name = "config.xml")
+    public void doConfigDotXml(StaplerRequest2 req, StaplerResponse2 rsp)
+            throws IOException {
+        if (Util.isOverridden(AbstractItem.class, getClass(), "doConfigDotXml", StaplerRequest.class, StaplerResponse.class)) {
+            doConfigDotXml(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            doConfigDotXmlImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doConfigDotXml(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
     public void doConfigDotXml(StaplerRequest req, StaplerResponse rsp)
             throws IOException {
+        doConfigDotXmlImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doConfigDotXmlImpl(StaplerRequest2 req, StaplerResponse2 rsp)
+            throws IOException {
         if (req.getMethod().equals("GET")) {
             // read
             rsp.setContentType("application/xml");
diff --git a/core/src/main/java/hudson/model/AbstractModelObject.java b/core/src/main/java/hudson/model/AbstractModelObject.java
index f6c7104f8e42..87b42527a86e 100644
--- a/core/src/main/java/hudson/model/AbstractModelObject.java
+++ b/core/src/main/java/hudson/model/AbstractModelObject.java
@@ -29,11 +29,14 @@
 import hudson.search.SearchIndex;
 import hudson.search.SearchIndexBuilder;
 import hudson.search.SearchableModelObject;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -45,33 +48,69 @@ public abstract class AbstractModelObject implements SearchableModelObject {
     /**
      * Displays the error in a page.
      */
-    protected final void sendError(Exception e, StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    protected final void sendError(Exception e, StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         req.setAttribute("exception", e);
         sendError(e.getMessage(), req, rsp);
     }
 
+    /**
+     * @deprecated use {@link #sendError(Exception, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    protected final void sendError(Exception e, StaplerRequest req, StaplerResponse rsp) throws javax.servlet.ServletException, IOException {
+        try {
+            sendError(e, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException ex) {
+            throw ServletExceptionWrapper.fromJakartaServletException(ex);
+        }
+    }
+
     protected final void sendError(Exception e) throws ServletException, IOException {
-        sendError(e, Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+        sendError(e, Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
     }
 
-    protected final void sendError(String message, StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    protected final void sendError(String message, StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         req.setAttribute("message", message);
         rsp.forward(this, "error", req);
     }
 
+    /**
+     * @deprecated use {@link #sendError(String, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    protected final void sendError(String message, StaplerRequest req, StaplerResponse rsp) throws javax.servlet.ServletException, IOException {
+        try {
+            sendError(message, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * @param pre
      *      If true, the message is put in a PRE tag.
      */
-    protected final void sendError(String message, StaplerRequest req, StaplerResponse rsp, boolean pre) throws ServletException, IOException {
+    protected final void sendError(String message, StaplerRequest2 req, StaplerResponse2 rsp, boolean pre) throws ServletException, IOException {
         req.setAttribute("message", message);
         if (pre)
             req.setAttribute("pre", true);
         rsp.forward(this, "error", req);
     }
 
+    /**
+     * @deprecated use {@link #sendError(String, StaplerRequest2, StaplerResponse2, boolean)}
+     */
+    @Deprecated
+    protected final void sendError(String message, StaplerRequest req, StaplerResponse rsp, boolean pre) throws javax.servlet.ServletException, IOException {
+        try {
+            sendError(message, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), pre);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     protected final void sendError(String message) throws ServletException, IOException {
-        sendError(message, Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+        sendError(message, Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
     }
 
     /**
@@ -82,7 +121,7 @@ protected final void sendError(String message) throws ServletException, IOExcept
      */
     @Deprecated
     protected final void requirePOST() throws ServletException {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req == null)  return; // invoked outside the context of servlet
         String method = req.getMethod();
         if (!method.equalsIgnoreCase("POST"))
diff --git a/core/src/main/java/hudson/model/AbstractProject.java b/core/src/main/java/hudson/model/AbstractProject.java
index 917ff1f7b81f..a380943687f7 100644
--- a/core/src/main/java/hudson/model/AbstractProject.java
+++ b/core/src/main/java/hudson/model/AbstractProject.java
@@ -77,6 +77,8 @@
 import hudson.util.AlternativeUiTextProvider.Message;
 import hudson.util.DescribableList;
 import hudson.util.FormValidation;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -96,7 +98,6 @@
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.BlockedBecauseOfBuildInProgress;
 import jenkins.model.Jenkins;
 import jenkins.model.ParameterizedJobMixIn;
@@ -120,7 +121,9 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
@@ -769,7 +772,7 @@ public List<ProminentProjectAction> getProminentActions() {
 
     @Override
     @POST
-    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         super.doConfigSubmit(req, rsp);
 
         updateTransientActions();
@@ -1726,10 +1729,14 @@ protected SearchIndexBuilder makeSearchIndex() {
 //
 //
 
-    /** @deprecated use {@link #doBuild(StaplerRequest, StaplerResponse, TimeDuration)} */
+    /** @deprecated use {@link #doBuild(StaplerRequest2, StaplerResponse2, TimeDuration)} */
     @Deprecated
-    public void doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
-        doBuild(req, rsp, TimeDuration.fromString(req.getParameter("delay")));
+    public void doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doBuild(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), TimeDuration.fromString(req.getParameter("delay")));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
     /**
@@ -1739,7 +1746,7 @@ public void doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException,
      *      Inject {@link TimeDuration}.
      */
     @Deprecated
-    public int getDelay(StaplerRequest req) throws ServletException {
+    public int getDelay(StaplerRequest req) throws javax.servlet.ServletException {
         String delay = req.getParameter("delay");
         if (delay == null)    return getQuietPeriod();
 
@@ -1749,26 +1756,59 @@ public int getDelay(StaplerRequest req) throws ServletException {
             if (delay.endsWith("secs"))  delay = delay.substring(0, delay.length() - 4);
             return Integer.parseInt(delay);
         } catch (NumberFormatException e) {
-            throw new ServletException("Invalid delay parameter value: " + delay, e);
+            throw new javax.servlet.ServletException("Invalid delay parameter value: " + delay, e);
         }
     }
 
-    /** @deprecated use {@link #doBuildWithParameters(StaplerRequest, StaplerResponse, TimeDuration)} */
+    /** @deprecated use {@link #doBuildWithParameters(StaplerRequest2, StaplerResponse2, TimeDuration)} */
     @Deprecated
-    public void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
-        doBuildWithParameters(req, rsp, TimeDuration.fromString(req.getParameter("delay")));
+    public void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doBuildWithParameters(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), TimeDuration.fromString(req.getParameter("delay")));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
     @Override // in case schedulePolling was overridden
-    public void doPolling(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doPolling(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         BuildAuthorizationToken.checkPermission((Job) this, authToken, req, rsp);
         schedulePolling();
         rsp.sendRedirect(".");
     }
 
+    /**
+     * @since TODO
+     */
+    @Override
+    protected void submit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(AbstractProject.class, getClass(), "submit", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            super.submit(req, rsp);
+            submitImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     @Override
-    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException, FormException {
         super.submit(req, rsp);
+        try {
+            submitImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void submitImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         JSONObject json = req.getSubmittedForm();
 
         makeDisabled(!json.optBoolean("enable"));
@@ -1835,14 +1875,18 @@ protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
 
     /**
      * @deprecated
-     *      As of 1.261. Use {@link #buildDescribable(StaplerRequest, List)} instead.
+     *      As of 1.261. Use {@link #buildDescribable(StaplerRequest2, List)} instead.
      */
     @Deprecated
-    protected final <T extends Describable<T>> List<T> buildDescribable(StaplerRequest req, List<? extends Descriptor<T>> descriptors, String prefix) throws FormException, ServletException {
-        return buildDescribable(req, descriptors);
+    protected final <T extends Describable<T>> List<T> buildDescribable(StaplerRequest req, List<? extends Descriptor<T>> descriptors, String prefix) throws FormException, javax.servlet.ServletException {
+        try {
+            return buildDescribable(StaplerRequest.toStaplerRequest2(req), descriptors);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
-    protected final <T extends Describable<T>> List<T> buildDescribable(StaplerRequest req, List<? extends Descriptor<T>> descriptors)
+    protected final <T extends Describable<T>> List<T> buildDescribable(StaplerRequest2 req, List<? extends Descriptor<T>> descriptors)
         throws FormException, ServletException {
 
         JSONObject data = req.getSubmittedForm();
@@ -1860,7 +1904,7 @@ protected final <T extends Describable<T>> List<T> buildDescribable(StaplerReque
     /**
      * Serves the workspace files.
      */
-    public DirectoryBrowserSupport doWs(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public DirectoryBrowserSupport doWs(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         checkPermission(Item.WORKSPACE);
         FilePath ws = getSomeWorkspace();
         if (ws == null || !ws.exists()) {
@@ -1887,7 +1931,7 @@ public DirectoryBrowserSupport doWs(StaplerRequest req, StaplerResponse rsp) thr
      * Wipes out the workspace.
      */
     @RequirePOST
-    public HttpResponse doDoWipeOutWorkspace() throws IOException, ServletException, InterruptedException {
+    public HttpResponse doDoWipeOutWorkspace() throws IOException, InterruptedException {
         checkPermission(Functions.isWipeOutPermissionEnabled() ? WIPEOUT : BUILD);
         R b = getSomeBuildWithWorkspace();
         FilePath ws = b != null ? b.getWorkspace() : null;
diff --git a/core/src/main/java/hudson/model/Actionable.java b/core/src/main/java/hudson/model/Actionable.java
index 7e3e695d9c4f..d8088319021b 100644
--- a/core/src/main/java/hudson/model/Actionable.java
+++ b/core/src/main/java/hudson/model/Actionable.java
@@ -37,8 +37,11 @@
 import java.util.logging.Logger;
 import jenkins.model.ModelObjectWithContextMenu;
 import jenkins.model.TransientActionFactory;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
@@ -338,7 +341,26 @@ public <T extends Action> T getAction(Class<T> type) {
         return null;
     }
 
+    /**
+     * @since TODO
+     */
+    public Object getDynamic(String token, StaplerRequest2 req, StaplerResponse2 rsp) {
+        if (Util.isOverridden(Actionable.class, getClass(), "getDynamic", String.class, StaplerRequest.class, StaplerResponse.class)) {
+            return getDynamic(token, StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            return getDynamicImpl(token, req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #getDynamic(String, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
+        return getDynamicImpl(token, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private Object getDynamicImpl(String token, StaplerRequest2 req, StaplerResponse2 rsp) {
         for (Action a : getAllActions()) {
             if (a == null)
                 continue;   // be defensive
@@ -351,7 +373,29 @@ public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp)
         return null;
     }
 
-    @Override public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    /**
+     * @since TODO
+     */
+    @Override
+    public ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
+        if (Util.isOverridden(Actionable.class, getClass(), "doContextMenu", StaplerRequest.class, StaplerResponse.class)) {
+            return doContextMenu(StaplerRequest.fromStaplerRequest2(request), StaplerResponse.fromStaplerResponse2(response));
+        } else {
+            return doContextMenuImpl(request, response);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doContextMenu(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    @Override
+    public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+        return doContextMenuImpl(StaplerRequest.toStaplerRequest2(request), StaplerResponse.toStaplerResponse2(response));
+    }
+
+    private ContextMenu doContextMenuImpl(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         return new ContextMenu().from(this, request, response);
     }
 
diff --git a/core/src/main/java/hudson/model/AdministrativeMonitor.java b/core/src/main/java/hudson/model/AdministrativeMonitor.java
index bdbfb48027d3..59518ba79e57 100644
--- a/core/src/main/java/hudson/model/AdministrativeMonitor.java
+++ b/core/src/main/java/hudson/model/AdministrativeMonitor.java
@@ -37,8 +37,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -175,7 +175,7 @@ public boolean isSecurity() {
      * URL binding to disable this monitor.
      */
     @RequirePOST
-    public void doDisable(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doDisable(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         disable(true);
         rsp.sendRedirect2(req.getContextPath() + "/manage");
@@ -188,7 +188,7 @@ public void doDisable(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
      *     Changing this permission check to return {@link Jenkins#SYSTEM_READ} will make the active
      *     administrative monitor appear on {@code manage.jelly} and on the globally visible
      *     {@link jenkins.management.AdministrativeMonitorsDecorator} to users without Administer permission.
-     *     {@link #doDisable(StaplerRequest, StaplerResponse)} will still always require Administer permission.
+     *     {@link #doDisable(StaplerRequest2, StaplerResponse2)} will still always require Administer permission.
      * </p>
      * <p>
      *     This method only allows for a single permission to be returned. If more complex permission checks are required,
diff --git a/core/src/main/java/hudson/model/AllView.java b/core/src/main/java/hudson/model/AllView.java
index ca1ef0d5cc0d..3972625ea7ab 100644
--- a/core/src/main/java/hudson/model/AllView.java
+++ b/core/src/main/java/hudson/model/AllView.java
@@ -26,7 +26,10 @@
 
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Extension;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.List;
@@ -34,12 +37,12 @@
 import java.util.Objects;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.util.SystemProperties;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -91,7 +94,7 @@ public String getDisplayName() {
 
     @RequirePOST
     @Override
-    public Item doCreateItem(StaplerRequest req, StaplerResponse rsp)
+    public Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException {
         ItemGroup<? extends TopLevelItem> ig = getOwner().getItemGroup();
         if (ig instanceof ModifiableItemGroup)
@@ -110,7 +113,24 @@ public String getPostConstructLandingPage() {
     }
 
     @Override
-    protected void submit(StaplerRequest req) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest2 req) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(AllView.class, getClass(), "submit", StaplerRequest.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            // noop
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2)}
+     */
+    @Deprecated
+    @Override
+    protected void submit(StaplerRequest req) throws IOException, javax.servlet.ServletException, FormException {
         // noop
     }
 
diff --git a/core/src/main/java/hudson/model/Api.java b/core/src/main/java/hudson/model/Api.java
index 23e72072112f..4b16e1b0b540 100644
--- a/core/src/main/java/hudson/model/Api.java
+++ b/core/src/main/java/hudson/model/Api.java
@@ -25,6 +25,10 @@
 package hudson.model;
 
 import hudson.ExtensionList;
+import hudson.Util;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.StringReader;
@@ -34,11 +38,10 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import javax.xml.transform.stream.StreamResult;
 import jenkins.model.Jenkins;
 import jenkins.security.SecureRequester;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.xml.FilteredFunctionContext;
 import org.dom4j.CharacterData;
 import org.dom4j.Document;
@@ -52,7 +55,9 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.Flavor;
 import org.kohsuke.stapler.export.Model;
@@ -96,7 +101,7 @@ public String getSearchUrl() {
     /**
      * Exposes the bean as XML.
      */
-    public void doXml(StaplerRequest req, StaplerResponse rsp,
+    public void doXml(StaplerRequest2 req, StaplerResponse2 rsp,
                       @QueryParameter String xpath,
                       @QueryParameter String wrapper,
                       @QueryParameter String tree,
@@ -212,7 +217,7 @@ private boolean isSimpleOutput(Object result) {
     /**
      * Generate schema.
      */
-    public void doSchema(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doSchema(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         setHeaders(rsp);
         rsp.setContentType("application/xml");
         StreamResult r = new StreamResult(rsp.getOutputStream());
@@ -223,7 +228,32 @@ public void doSchema(StaplerRequest req, StaplerResponse rsp) throws IOException
     /**
      * Exposes the bean as JSON.
      */
-    public void doJson(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doJson(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Api.class, getClass(), "doJson", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doJson(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doJsonImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doJson(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doJson(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doJsonImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doJsonImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         if (req.getParameter("jsonp") == null || permit(req)) {
             setHeaders(rsp);
             rsp.serveExposedBean(req, bean, req.getParameter("jsonp") == null ? Flavor.JSON : Flavor.JSONP);
@@ -235,12 +265,37 @@ public void doJson(StaplerRequest req, StaplerResponse rsp) throws IOException,
     /**
      * Exposes the bean as Python literal.
      */
-    public void doPython(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doPython(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Api.class, getClass(), "doPython", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doPython(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doPythonImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doPython(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doPython(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doPythonImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doPythonImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         setHeaders(rsp);
         rsp.serveExposedBean(req, bean, Flavor.PYTHON);
     }
 
-    private boolean permit(StaplerRequest req) {
+    private boolean permit(StaplerRequest2 req) {
         for (SecureRequester r : ExtensionList.lookup(SecureRequester.class)) {
             if (r.permit(req, bean)) {
                 return true;
@@ -250,7 +305,7 @@ private boolean permit(StaplerRequest req) {
     }
 
     @Restricted(NoExternalUse.class)
-    protected void setHeaders(StaplerResponse rsp) {
+    protected void setHeaders(StaplerResponse2 rsp) {
         rsp.setHeader("X-Jenkins", Jenkins.VERSION);
         rsp.setHeader("X-Jenkins-Session", Jenkins.SESSION_HASH);
         // to be really defensive against dumb browsers not taking into consideration the content-type being set
diff --git a/core/src/main/java/hudson/model/AutoCompletionCandidates.java b/core/src/main/java/hudson/model/AutoCompletionCandidates.java
index d2f5f17c255f..366f626e3144 100644
--- a/core/src/main/java/hudson/model/AutoCompletionCandidates.java
+++ b/core/src/main/java/hudson/model/AutoCompletionCandidates.java
@@ -28,16 +28,16 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.search.Search;
 import hudson.search.UserSearchProperty;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Locale;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Flavor;
 
 /**
@@ -69,7 +69,7 @@ public List<String> getValues() {
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object o) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object o) throws IOException, ServletException {
         Search.Result r = new Search.Result();
         for (String value : values) {
             r.suggestions.add(new hudson.search.Search.Item(value));
diff --git a/core/src/main/java/hudson/model/BallColor.java b/core/src/main/java/hudson/model/BallColor.java
index 5913f59466f9..3e8dc2f28802 100644
--- a/core/src/main/java/hudson/model/BallColor.java
+++ b/core/src/main/java/hudson/model/BallColor.java
@@ -113,7 +113,7 @@ public String getImage() {
 
     @Override
     public String getImageOf(String size) {
-        return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH + "/images/" + size + '/' + image;
+        return Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH + "/images/" + size + '/' + image;
     }
 
     /**
diff --git a/core/src/main/java/hudson/model/BooleanParameterDefinition.java b/core/src/main/java/hudson/model/BooleanParameterDefinition.java
index 6e9db32216fd..6bf1a50096e3 100644
--- a/core/src/main/java/hudson/model/BooleanParameterDefinition.java
+++ b/core/src/main/java/hudson/model/BooleanParameterDefinition.java
@@ -33,7 +33,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link ParameterDefinition} that is either 'true' or 'false'.
@@ -79,7 +79,7 @@ public void setDefaultValue(boolean defaultValue) {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         BooleanParameterValue value = req.bindJSON(BooleanParameterValue.class, jo);
         value.setDescription(getDescription());
         return value;
diff --git a/core/src/main/java/hudson/model/BuildAuthorizationToken.java b/core/src/main/java/hudson/model/BuildAuthorizationToken.java
index a09ed113e1cf..3611824fb54d 100644
--- a/core/src/main/java/hudson/model/BuildAuthorizationToken.java
+++ b/core/src/main/java/hudson/model/BuildAuthorizationToken.java
@@ -27,11 +27,13 @@
 import com.thoughtworks.xstream.converters.basic.AbstractSingleValueConverter;
 import hudson.Util;
 import hudson.security.ACL;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.access.AccessDeniedException;
 
 /**
@@ -51,7 +53,10 @@ public BuildAuthorizationToken(String token) {
         this.token = token;
     }
 
-    public static BuildAuthorizationToken create(StaplerRequest req) {
+    /**
+     * @since TODO
+     */
+    public static BuildAuthorizationToken create(StaplerRequest2 req) {
         if (req.getParameter("pseudoRemoteTrigger") != null) {
             String token = Util.fixEmpty(req.getParameter("authToken"));
             if (token != null)
@@ -61,11 +66,22 @@ public static BuildAuthorizationToken create(StaplerRequest req) {
         return null;
     }
 
+    /**
+     * @deprecated use {@link #create(StaplerRequest2)}
+     */
+    @Deprecated
+    public static BuildAuthorizationToken create(StaplerRequest req) {
+        return create(StaplerRequest.toStaplerRequest2(req));
+    }
+
     @Deprecated public static void checkPermission(AbstractProject<?, ?> project, BuildAuthorizationToken token, StaplerRequest req, StaplerResponse rsp) throws IOException {
-        checkPermission((Job<?, ?>) project, token, req, rsp);
+        checkPermission((Job<?, ?>) project, token, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
     }
 
-    public static void checkPermission(Job<?, ?> project, BuildAuthorizationToken token, StaplerRequest req, StaplerResponse rsp) throws IOException {
+    /**
+     * @since TODO
+     */
+    public static void checkPermission(Job<?, ?> project, BuildAuthorizationToken token, StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (token != null && token.token != null) {
             //check the provided token
             String providedToken = req.getParameter("token");
@@ -86,6 +102,14 @@ public static void checkPermission(Job<?, ?> project, BuildAuthorizationToken to
         throw HttpResponses.forwardToView(project, "requirePOST.jelly");
     }
 
+    /**
+     * @deprecated use {@link #checkPermission(Job, BuildAuthorizationToken, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    public static void checkPermission(Job<?, ?> project, BuildAuthorizationToken token, StaplerRequest req, StaplerResponse rsp) throws IOException {
+        checkPermission(project, token, StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
     public String getToken() {
         return token;
     }
diff --git a/core/src/main/java/hudson/model/BuildTimelineWidget.java b/core/src/main/java/hudson/model/BuildTimelineWidget.java
index 9691969162d4..4f5ccbf1c67a 100644
--- a/core/src/main/java/hudson/model/BuildTimelineWidget.java
+++ b/core/src/main/java/hudson/model/BuildTimelineWidget.java
@@ -25,12 +25,15 @@
 package hudson.model;
 
 import hudson.util.RunList;
+import jakarta.servlet.ServletException;
+import java.io.IOException;
 import java.util.ArrayList;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * UI widget for showing the SIMILE timeline control.
@@ -60,12 +63,15 @@ public BuildTimelineWidget(RunList<?> builds) {
         return builds.getLastBuild();
     }
 
-    public HttpResponse doData(StaplerRequest req, @QueryParameter long min, @QueryParameter long max) {
-        return (req1, rsp, node) -> {
-            JSONObject o = new JSONObject();
-            o.put("events", JSONArray.fromObject(new ArrayList<>()));
-            rsp.setContentType("text/javascript;charset=UTF-8");
-            o.write(rsp.getWriter());
+    public HttpResponse doData(StaplerRequest2 req, @QueryParameter long min, @QueryParameter long max) {
+        return new HttpResponse() {
+            @Override
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
+                JSONObject o = new JSONObject();
+                o.put("events", JSONArray.fromObject(new ArrayList<>()));
+                rsp.setContentType("text/javascript;charset=UTF-8");
+                o.write(rsp.getWriter());
+            }
         };
     }
 
diff --git a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java
index 7b12a9b2cee3..98bdcf2e8072 100644
--- a/core/src/main/java/hudson/model/ChoiceParameterDefinition.java
+++ b/core/src/main/java/hudson/model/ChoiceParameterDefinition.java
@@ -20,7 +20,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 
 /**
@@ -152,7 +152,7 @@ public boolean isValid(ParameterValue value) {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         StringParameterValue value = req.bindJSON(StringParameterValue.class, jo);
         value.setDescription(getDescription());
         checkValue(value, value.getValue());
@@ -218,7 +218,7 @@ public String getHelpFile() {
         /*
          * We need this for JENKINS-26143 -- reflective creation cannot handle setChoices(Object). See that method for context.
          */
-        public ParameterDefinition newInstance(@Nullable StaplerRequest req, @NonNull JSONObject formData) throws FormException {
+        public ParameterDefinition newInstance(@Nullable StaplerRequest2 req, @NonNull JSONObject formData) throws FormException {
             String name = formData.getString("name");
             String desc = formData.getString("description");
             String choiceText = formData.getString("choices");
diff --git a/core/src/main/java/hudson/model/Computer.java b/core/src/main/java/hudson/model/Computer.java
index 14a311381a37..a4878a2c8f91 100644
--- a/core/src/main/java/hudson/model/Computer.java
+++ b/core/src/main/java/hudson/model/Computer.java
@@ -26,7 +26,7 @@
 
 package hudson.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -73,6 +73,7 @@
 import hudson.util.RemotingDiagnostics;
 import hudson.util.RemotingDiagnostics.HeapDump;
 import hudson.util.RunList;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -105,7 +106,6 @@
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.security.ImpersonatingExecutorService;
 import jenkins.security.MasterToSlaveCallable;
@@ -129,8 +129,8 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -227,7 +227,7 @@
      * @since 1.607
      */
     public void recordTermination() {
-        StaplerRequest request = Stapler.getCurrentRequest();
+        StaplerRequest2 request = Stapler.getCurrentRequest2();
         if (request != null) {
             terminatedBy.add(new TerminationRequest(
                     String.format("Termination requested at %s by %s [id=%d] from HTTP request for %s",
@@ -416,7 +416,7 @@ public String getOfflineCauseReason() {
     /**
      * If {@link #getChannel()}==null, attempts to relaunch the agent.
      */
-    public abstract void doLaunchSlaveAgent(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException;
+    public abstract void doLaunchSlaveAgent(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException;
 
     /**
      * @deprecated since 2009-01-06.  Use {@link #connect(boolean)}
@@ -427,7 +427,7 @@ public final void launch() {
     }
 
     /**
-     * Do the same as {@link #doLaunchSlaveAgent(StaplerRequest, StaplerResponse)}
+     * Do the same as {@link #doLaunchSlaveAgent(StaplerRequest2, StaplerResponse2)}
      * but outside the context of serving a request.
      *
      * <p>
@@ -1391,12 +1391,12 @@ public String call() throws IOException {
 //
 //
     @Restricted(DoNotUse.class)
-    public void doRssAll(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssAll(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (all builds)", getUrl(), getBuilds());
     }
 
     @Restricted(DoNotUse.class)
-    public void doRssFailed(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssFailed(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (failed builds)", getUrl(), getBuilds().failureOnly());
     }
 
@@ -1407,7 +1407,7 @@ public void doRssFailed(StaplerRequest req, StaplerResponse rsp) throws IOExcept
      * @since 2.215
      */
     @Restricted(DoNotUse.class)
-    public void doRssLatest(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssLatest(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         final List<Run> lastBuilds = new ArrayList<>();
         for (AbstractProject<?, ?> p : Jenkins.get().allItems(AbstractProject.class)) {
             if (p.getLastBuild() != null) {
@@ -1452,7 +1452,7 @@ public Api getApi() {
     /**
      * Dumps the contents of the export table.
      */
-    public void doDumpExportTable(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public void doDumpExportTable(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         // this is a debug probe and may expose sensitive information
         checkPermission(Jenkins.ADMINISTER);
 
@@ -1488,18 +1488,18 @@ public String call() throws IOException {
      * For system diagnostics.
      * Run arbitrary Groovy script.
      */
-    public void doScript(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScript(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         _doScript(req, rsp, "_script.jelly");
     }
 
     /**
      * Run arbitrary Groovy script and return result as plain text.
      */
-    public void doScriptText(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScriptText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         _doScript(req, rsp, "_scriptText.jelly");
     }
 
-    protected void _doScript(StaplerRequest req, StaplerResponse rsp, String view) throws IOException, ServletException {
+    protected void _doScript(StaplerRequest2 req, StaplerResponse2 rsp, String view) throws IOException, ServletException {
         Jenkins._doScript(req, rsp, req.getView(this, view), getChannel(), getACL());
     }
 
@@ -1507,7 +1507,7 @@ protected void _doScript(StaplerRequest req, StaplerResponse rsp, String view) t
      * Accepts the update to the node configuration.
      */
     @POST
-    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         checkPermission(CONFIGURE);
 
         String proposedName = Util.fixEmptyAndTrim(req.getSubmittedForm().getString("name"));
@@ -1547,7 +1547,7 @@ public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOExc
      * Accepts {@code config.xml} submission, as well as serve it.
      */
     @WebMethod(name = "config.xml")
-    public void doConfigDotXml(StaplerRequest req, StaplerResponse rsp)
+    public void doConfigDotXml(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException {
 
         if (req.getMethod().equals("GET")) {
@@ -1626,7 +1626,7 @@ public void waitUntilOffline() throws InterruptedException {
     /**
      * Handles incremental log.
      */
-    public void doProgressiveLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doProgressiveLog(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         getLogText().doProgressText(req, rsp);
     }
 
diff --git a/core/src/main/java/hudson/model/ComputerSet.java b/core/src/main/java/hudson/model/ComputerSet.java
index 5cb798978dea..f25d25a19a50 100644
--- a/core/src/main/java/hudson/model/ComputerSet.java
+++ b/core/src/main/java/hudson/model/ComputerSet.java
@@ -41,6 +41,7 @@
 import hudson.util.DescribableList;
 import hudson.util.FormApply;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -52,7 +53,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.ModelObjectWithChildren;
 import jenkins.model.ModelObjectWithContextMenu.ContextMenu;
@@ -61,8 +61,8 @@
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -112,7 +112,7 @@ public Computer[] get_all() {
     }
 
     @Override
-    public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ContextMenu m = new ContextMenu();
         for (Computer c : get_all()) {
             m.add(c);
@@ -206,12 +206,12 @@ public String getSearchUrl() {
         return "/computers/";
     }
 
-    public Computer getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
+    public Computer getDynamic(String token, StaplerRequest2 req, StaplerResponse2 rsp) {
         return Jenkins.get().getComputer(token);
     }
 
     @RequirePOST
-    public void do_launchAll(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void do_launchAll(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         for (Computer c : get_all()) {
@@ -227,7 +227,7 @@ public void do_launchAll(StaplerRequest req, StaplerResponse rsp) throws IOExcep
      * TODO: ajax on the client side to wait until the update completion might be nice.
      */
     @RequirePOST
-    public void doUpdateNow(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doUpdateNow(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.MANAGE);
 
         for (NodeMonitor nodeMonitor : NodeMonitor.getAll()) {
@@ -244,7 +244,7 @@ public void doUpdateNow(StaplerRequest req, StaplerResponse rsp) throws IOExcept
      * First check point in creating a new agent.
      */
     @RequirePOST
-    public synchronized void doCreateItem(StaplerRequest req, StaplerResponse rsp,
+    public synchronized void doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp,
                                            @QueryParameter String name, @QueryParameter String mode,
                                            @QueryParameter String from) throws IOException, ServletException {
         final Jenkins app = Jenkins.get();
@@ -290,7 +290,7 @@ public synchronized void doCreateItem(StaplerRequest req, StaplerResponse rsp,
      * Really creates a new agent.
      */
     @POST
-    public synchronized void doDoCreateItem(StaplerRequest req, StaplerResponse rsp,
+    public synchronized void doDoCreateItem(StaplerRequest2 req, StaplerResponse2 rsp,
                                            @QueryParameter String name,
                                            @QueryParameter String type) throws IOException, ServletException, FormException {
         final Jenkins app = Jenkins.get();
@@ -348,7 +348,7 @@ public FormValidation doCheckName(@QueryParameter String value) throws IOExcepti
      * Accepts submission from the configuration page.
      */
     @POST
-    public synchronized HttpResponse doConfigSubmit(StaplerRequest req) throws IOException, ServletException, FormException {
+    public synchronized HttpResponse doConfigSubmit(StaplerRequest2 req) throws IOException, ServletException, FormException {
         BulkChange bc = new BulkChange(MONITORS_OWNER);
         try {
             Jenkins.get().checkPermission(Jenkins.MANAGE);
diff --git a/core/src/main/java/hudson/model/Descriptor.java b/core/src/main/java/hudson/model/Descriptor.java
index b5eb07784d27..e2067bfc6944 100644
--- a/core/src/main/java/hudson/model/Descriptor.java
+++ b/core/src/main/java/hudson/model/Descriptor.java
@@ -25,7 +25,7 @@
 package hudson.model;
 
 import static hudson.util.QuotedStringTokenizer.quote;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -45,6 +45,9 @@
 import hudson.util.ReflectionUtils;
 import hudson.util.ReflectionUtils.Parameter;
 import hudson.views.ListViewColumn;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
 import java.beans.Introspector;
 import java.io.File;
 import java.io.IOException;
@@ -71,13 +74,12 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
 import jenkins.model.GlobalConfiguration;
 import jenkins.model.GlobalConfigurationCategory;
 import jenkins.model.Jenkins;
 import jenkins.model.Loadable;
 import jenkins.security.RedactSecretJsonInErrorMessageSanitizer;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.io.OnMaster;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
@@ -92,7 +94,9 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 import org.kohsuke.stapler.jelly.JellyCompatibleFacet;
 import org.kohsuke.stapler.lang.Klass;
@@ -382,7 +386,7 @@ public final String getDescriptorFullUrl() {
      * @since 1.402
      */
     public static String getCurrentDescriptorByNameUrl() {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
 
         // this override allows RenderOnDemandClosure to preserve the proper value
         Object url = req.getAttribute("currentDescriptorByNameUrl");
@@ -576,16 +580,33 @@ public T newInstance(StaplerRequest req) throws FormException {
      *
      * @throws FormException
      *      Signals a problem in the submitted form.
+     * @since TODO
+     */
+    public T newInstance(@Nullable StaplerRequest2 req, @NonNull JSONObject formData) throws FormException {
+        if (Util.isOverridden(Descriptor.class, getClass(), "newInstance", StaplerRequest.class, JSONObject.class)) {
+            return newInstance(req != null ? StaplerRequest.fromStaplerRequest2(req) : null, formData);
+        } else {
+            return newInstanceImpl(req, formData);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #newInstance(StaplerRequest2, JSONObject)}
      * @since 1.145
      */
+    @Deprecated
     public T newInstance(@Nullable StaplerRequest req, @NonNull JSONObject formData) throws FormException {
+        return newInstanceImpl(req != null ? StaplerRequest.toStaplerRequest2(req) : null, formData);
+    }
+
+    private T newInstanceImpl(@Nullable StaplerRequest2 req, @NonNull JSONObject formData) throws FormException {
         try {
             Method m = getClass().getMethod("newInstance", StaplerRequest.class);
 
             if (!Modifier.isAbstract(m.getDeclaringClass().getModifiers())) {
                 // this class overrides newInstance(StaplerRequest).
                 // maintain the backward compatible behavior
-                return verifyNewInstance(newInstance(req));
+                return verifyNewInstance(newInstance(StaplerRequest.fromStaplerRequest2(req)));
             } else {
                 if (req == null) {
                     // yes, req is supposed to be always non-null, but see the note above
@@ -602,16 +623,25 @@ public T newInstance(@Nullable StaplerRequest req, @NonNull JSONObject formData)
     }
 
     /**
-     * Replacement for {@link StaplerRequest#bindJSON(Class, JSONObject)} which honors {@link #newInstance(StaplerRequest, JSONObject)}.
-     * This is automatically used inside {@link #newInstance(StaplerRequest, JSONObject)} so a direct call would only be necessary
-     * in case the top level binding might use a {@link Descriptor} which overrides {@link #newInstance(StaplerRequest, JSONObject)}.
+     * Replacement for {@link StaplerRequest2#bindJSON(Class, JSONObject)} which honors {@link #newInstance(StaplerRequest2, JSONObject)}.
+     * This is automatically used inside {@link #newInstance(StaplerRequest2, JSONObject)} so a direct call would only be necessary
+     * in case the top level binding might use a {@link Descriptor} which overrides {@link #newInstance(StaplerRequest2, JSONObject)}.
+     * @since TODO
+     */
+    public static <T> T bindJSON(StaplerRequest2 req, Class<T> type, JSONObject src) {
+        return bindJSON(req, type, src, false);
+    }
+
+    /**
+     * @deprecated use {@link #bindJSON(StaplerRequest2, Class, JSONObject)}
      * @since 2.342
      */
+    @Deprecated
     public static <T> T bindJSON(StaplerRequest req, Class<T> type, JSONObject src) {
-        return bindJSON(req, type, src, false);
+        return bindJSON(StaplerRequest.toStaplerRequest2(req), type, src);
     }
 
-    private static <T> T bindJSON(StaplerRequest req, Class<T> type, JSONObject src, boolean fromNewInstance) {
+    private static <T> T bindJSON(StaplerRequest2 req, Class<T> type, JSONObject src, boolean fromNewInstance) {
         BindInterceptor oldInterceptor = req.getBindInterceptor();
         try {
             NewInstanceBindInterceptor interceptor;
@@ -631,9 +661,9 @@ private static <T> T bindJSON(StaplerRequest req, Class<T> type, JSONObject src,
     }
 
     /**
-     * Ensures that calls to {@link StaplerRequest#bindJSON(Class, JSONObject)} from {@link #newInstance(StaplerRequest, JSONObject)} recurse properly.
+     * Ensures that calls to {@link StaplerRequest2#bindJSON(Class, JSONObject)} from {@link #newInstance(StaplerRequest2, JSONObject)} recurse properly.
      * {@code doConfigSubmit}-like methods will wind up calling {@code newInstance} directly
-     * or via {@link #newInstancesFromHeteroList(StaplerRequest, Object, Collection)},
+     * or via {@link #newInstancesFromHeteroList(StaplerRequest2, Object, Collection)},
      * which consult any custom {@code newInstance} overrides for top-level {@link Describable} objects.
      * But for nested describable objects Stapler would know nothing about {@code newInstance} without this trick.
      */
@@ -671,7 +701,7 @@ public Object instantiate(Class actualType, JSONObject json) {
                 try {
                     final Descriptor descriptor = Jenkins.get().getDescriptor(actualType);
                     if (descriptor != null) {
-                        return descriptor.newInstance(Stapler.getCurrentRequest(), json);
+                        return descriptor.newInstance(Stapler.getCurrentRequest2(), json);
                     } else {
                         LOGGER.log(Level.WARNING, "Descriptor not found. Falling back to default instantiation "
                                 + actualType.getName() + " " + json);
@@ -694,7 +724,7 @@ public Object onConvert(Type targetType, Class targetTypeErasure, Object jsonSou
                 if (isApplicable(targetTypeErasure, json)) {
                     LOGGER.log(Level.FINE, "switching to newInstance {0} {1}", new Object[] {targetTypeErasure.getName(), json});
                     try {
-                        return Jenkins.get().getDescriptor(targetTypeErasure).newInstance(Stapler.getCurrentRequest(), json);
+                        return Jenkins.get().getDescriptor(targetTypeErasure).newInstance(Stapler.getCurrentRequest2(), json);
                     } catch (Exception x) {
                         LOGGER.log(Level.WARNING, "falling back to default instantiation " + targetTypeErasure.getName() + " " + json, x);
                     }
@@ -776,13 +806,13 @@ public String getHelpFile(Klass<?> clazz, String fieldName) {
             }
 
             try {
-                if (Stapler.getCurrentRequest().getView(c, "help" + suffix) != null)
+                if (Stapler.getCurrentRequest2().getView(c, "help" + suffix) != null)
                     return page;
             } catch (IOException e) {
                 throw new Error(e);
             }
 
-            if (getStaticHelpUrl(Stapler.getCurrentRequest(), c, suffix) != null)    return page;
+            if (getStaticHelpUrl(Stapler.getCurrentRequest2(), c, suffix) != null)    return page;
         }
         return null;
     }
@@ -812,7 +842,7 @@ public final boolean isSubTypeOf(Class type) {
 
     /**
      * @deprecated
-     *      As of 1.239, use {@link #configure(StaplerRequest, JSONObject)}.
+     *      As of 1.239, use {@link #configure(StaplerRequest2, JSONObject)}.
      */
     @Deprecated
     public boolean configure(StaplerRequest req) throws FormException {
@@ -829,7 +859,21 @@ public boolean configure(StaplerRequest req) throws FormException {
      *      See <a href="https://www.jenkins.io/doc/developer/forms/structured-form-submission/">the developer documentation</a>.
      * @return false
      *      to keep the client in the same config page.
+     * @since TODO
      */
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
+        if (Util.isOverridden(Descriptor.class, getClass(), "configure", StaplerRequest.class, JSONObject.class)) {
+            return configure(StaplerRequest.fromStaplerRequest2(req), json);
+        } else {
+            // compatibility
+            return configure(StaplerRequest.fromStaplerRequest2(req));
+        }
+    }
+
+    /**
+     * @deprecated use {@link #configure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
     public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
         // compatibility
         return configure(req);
@@ -895,7 +939,7 @@ protected final String getViewPage(Class<?> clazz, String pageName) {
 
     protected List<String> getPossibleViewNames(String baseName) {
         List<String> names = new ArrayList<>();
-        for (Facet f : WebApp.get(Jenkins.get().servletContext).facets) {
+        for (Facet f : WebApp.get(Jenkins.get().getServletContext()).facets) {
             if (f instanceof JellyCompatibleFacet jcf) {
                 for (String ext : jcf.getScriptExtensions())
                     names.add(baseName + ext);
@@ -957,7 +1001,32 @@ protected PluginWrapper getPlugin() {
     /**
      * Serves {@code help.html} from the resource of {@link #clazz}.
      */
-    public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doHelp(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Descriptor.class, getClass(), "doHelp", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doHelp(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doHelpImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doHelp(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doHelpImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doHelpImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String path = req.getRestOfPath();
         if (path.contains("..")) throw new ServletException("Illegal path: " + path);
 
@@ -972,13 +1041,13 @@ public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException,
         }
 
         for (Klass<?> c = getKlass(); c != null; c = c.getSuperClass()) {
-            RequestDispatcher rd = Stapler.getCurrentRequest().getView(c, "help" + path);
+            RequestDispatcher rd = Stapler.getCurrentRequest2().getView(c, "help" + path);
             if (rd != null) { // template based help page
                 rd.forward(req, rsp);
                 return;
             }
 
-            URL url = getStaticHelpUrl(Stapler.getCurrentRequest(), c, path);
+            URL url = getStaticHelpUrl(Stapler.getCurrentRequest2(), c, path);
             if (url != null) {
                 // TODO: generalize macro expansion and perhaps even support JEXL
                 rsp.setContentType("text/html;charset=UTF-8");
@@ -992,8 +1061,11 @@ public void doHelp(StaplerRequest req, StaplerResponse rsp) throws IOException,
         rsp.sendError(SC_NOT_FOUND);
     }
 
+    /**
+     * @since TODO
+     */
     @Restricted(NoExternalUse.class)
-    public static URL getStaticHelpUrl(StaplerRequest req, Klass<?> c, String suffix) {
+    public static URL getStaticHelpUrl(StaplerRequest2 req, Klass<?> c, String suffix) {
 
         String base = "help" + suffix;
         URL url;
@@ -1017,6 +1089,15 @@ public static URL getStaticHelpUrl(StaplerRequest req, Klass<?> c, String suffix
         return c.getResource(base + ".html");
     }
 
+    /**
+     * @deprecated use {@link #getStaticHelpUrl(StaplerRequest2, Klass, String)}
+     */
+    @Deprecated
+    @Restricted(NoExternalUse.class)
+    public static URL getStaticHelpUrl(StaplerRequest req, Klass<?> c, String suffix) {
+        return getStaticHelpUrl(StaplerRequest.toStaplerRequest2(req), c, suffix);
+    }
+
 
 //
 // static methods
@@ -1061,16 +1142,30 @@ Map<Descriptor<T>, T> toMap(Iterable<T> describables) {
      *      List of descriptors to create instances from.
      * @return
      *      Can be empty but never null.
+     * @since TODO
      */
     public static <T extends Describable<T>>
-    List<T> newInstancesFromHeteroList(StaplerRequest req, JSONObject formData, String key,
+    List<T> newInstancesFromHeteroList(StaplerRequest2 req, JSONObject formData, String key,
                 Collection<? extends Descriptor<T>> descriptors) throws FormException {
 
         return newInstancesFromHeteroList(req, formData.get(key), descriptors);
     }
 
+    /**
+     * @deprecated use {@link #newInstancesFromHeteroList(StaplerRequest2, JSONObject, String, Collection)}
+     */
+    @Deprecated
+    public static <T extends Describable<T>>
+    List<T> newInstancesFromHeteroList(StaplerRequest req, JSONObject formData, String key,
+                                       Collection<? extends Descriptor<T>> descriptors) throws FormException {
+        return newInstancesFromHeteroList(StaplerRequest.toStaplerRequest2(req), formData, key, descriptors);
+    }
+
+    /**
+     * @since TODO
+     */
     public static <T extends Describable<T>>
-    List<T> newInstancesFromHeteroList(StaplerRequest req, Object formData,
+    List<T> newInstancesFromHeteroList(StaplerRequest2 req, Object formData,
                 Collection<? extends Descriptor<T>> descriptors) throws FormException {
 
         List<T> items = new ArrayList<>();
@@ -1086,7 +1181,7 @@ List<T> newInstancesFromHeteroList(StaplerRequest req, Object formData,
                 if (kind != null) {
                     // Only applies when Descriptor.getId is overridden.
                     // Note that kind is only supported here,
-                    // *not* inside the StaplerRequest.bindJSON which is normally called by newInstance
+                    // *not* inside the StaplerRequest2.bindJSON which is normally called by newInstance
                     // (since Descriptor.newInstance is not itself available to Stapler).
                     // If you merely override getId for some reason, but use @DataBoundConstructor on your Describable,
                     // there is no problem; but you can only rely on newInstance being called at top level.
@@ -1114,6 +1209,16 @@ List<T> newInstancesFromHeteroList(StaplerRequest req, Object formData,
         return items;
     }
 
+    /**
+     * @deprecated use {@link #newInstancesFromHeteroList(StaplerRequest2, JSONObject, String, Collection)}
+     */
+    @Deprecated
+    public static <T extends Describable<T>>
+    List<T> newInstancesFromHeteroList(StaplerRequest req, Object formData,
+                                       Collection<? extends Descriptor<T>> descriptors) throws FormException {
+        return newInstancesFromHeteroList(StaplerRequest.toStaplerRequest2(req), formData, descriptors);
+    }
+
     /**
      * Finds a descriptor from a collection by its ID.
      * @param id should match {@link #getId}
@@ -1199,7 +1304,7 @@ public String getFormField() {
         }
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             if (FormApply.isApply(req)) {
                 FormApply.applyResponse("notificationBar.show(" + quote(getMessage()) + ",notificationBar.ERROR)")
                         .generateResponse(req, rsp, node);
diff --git a/core/src/main/java/hudson/model/DirectlyModifiableView.java b/core/src/main/java/hudson/model/DirectlyModifiableView.java
index 61362272c248..138f33a6a32c 100644
--- a/core/src/main/java/hudson/model/DirectlyModifiableView.java
+++ b/core/src/main/java/hudson/model/DirectlyModifiableView.java
@@ -26,8 +26,8 @@
 
 
 import edu.umd.cs.findbugs.annotations.NonNull;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.interceptor.RequirePOST;
diff --git a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java
index 9d455f4c1bd3..72da0c7514c1 100644
--- a/core/src/main/java/hudson/model/DirectoryBrowserSupport.java
+++ b/core/src/main/java/hudson/model/DirectoryBrowserSupport.java
@@ -27,6 +27,9 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.FilePath;
 import hudson.Util;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -55,8 +58,6 @@
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.security.MasterToSlaveCallable;
 import jenkins.security.ResourceDomainConfiguration;
@@ -70,7 +71,9 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Has convenience methods to serve file system.
@@ -157,7 +160,7 @@ public DirectoryBrowserSupport(ModelObject owner, VirtualFile base, String title
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         if (!ResourceDomainConfiguration.isResourceRequest(req) && ResourceDomainConfiguration.isResourceDomainConfigured()) {
             resourceToken = ResourceDomainRootAction.get().getToken(this, req);
         }
@@ -191,11 +194,15 @@ public void setIndexFileName(String fileName) {
      *      from the {@code doXYZ} method and let Stapler generate a response for you.
      */
     @Deprecated
-    public void serveFile(StaplerRequest req, StaplerResponse rsp, FilePath root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException {
-        serveFile(req, rsp, root.toVirtualFile(), icon, serveDirIndex);
+    public void serveFile(StaplerRequest req, StaplerResponse rsp, FilePath root, String icon, boolean serveDirIndex) throws IOException, javax.servlet.ServletException, InterruptedException {
+        try {
+            serveFile(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), root.toVirtualFile(), icon, serveDirIndex);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
-    private void serveFile(StaplerRequest req, StaplerResponse rsp, VirtualFile root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException {
+    private void serveFile(StaplerRequest2 req, StaplerResponse2 rsp, VirtualFile root, String icon, boolean serveDirIndex) throws IOException, ServletException, InterruptedException {
         // handle form submission
         String pattern = req.getParameter("pattern");
         if (pattern == null)
@@ -492,7 +499,7 @@ private boolean isDescendant(VirtualFile root, String relativePath) {
         }
     }
 
-    private String getPath(StaplerRequest req) {
+    private String getPath(StaplerRequest2 req) {
         String path = req.getRestOfPath();
         if (path.isEmpty())
             path = "/";
@@ -521,7 +528,7 @@ private static String createBackRef(int times) {
         return "../".repeat(times);
     }
 
-    private static void zip(StaplerResponse rsp, VirtualFile root, VirtualFile dir, String glob) throws IOException, InterruptedException {
+    private static void zip(StaplerResponse2 rsp, VirtualFile root, VirtualFile dir, String glob) throws IOException, InterruptedException {
         OutputStream outputStream = rsp.getOutputStream();
         try (ZipOutputStream zos = new ZipOutputStream(outputStream)) {
             zos.setEncoding(Charset.defaultCharset().displayName()); // TODO JENKINS-20663 make this overridable via query parameter
diff --git a/core/src/main/java/hudson/model/Executor.java b/core/src/main/java/hudson/model/Executor.java
index 020399bdd5b8..94aa1c770d21 100644
--- a/core/src/main/java/hudson/model/Executor.java
+++ b/core/src/main/java/hudson/model/Executor.java
@@ -59,7 +59,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
-import javax.servlet.ServletException;
 import jenkins.model.CauseOfInterruption;
 import jenkins.model.CauseOfInterruption.UserInterruption;
 import jenkins.model.InterruptedBuildAction;
@@ -852,7 +851,7 @@ public void start() {
      */
     @RequirePOST
     @Deprecated
-    public void doStop(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doStop(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
         doStop().generateResponse(req, rsp, this);
     }
 
diff --git a/core/src/main/java/hudson/model/Failure.java b/core/src/main/java/hudson/model/Failure.java
index 71318dd0464b..0546f0a7e090 100644
--- a/core/src/main/java/hudson/model/Failure.java
+++ b/core/src/main/java/hudson/model/Failure.java
@@ -25,12 +25,12 @@
 package hudson.model;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Represents an error induced by user, encountered during HTTP request processing.
@@ -55,7 +55,7 @@ public Failure(String message, boolean pre) {
         this.pre = pre;
     }
 
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node, @CheckForNull Throwable throwable) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node, @CheckForNull Throwable throwable) throws IOException, ServletException {
         if (throwable != null) {
             req.setAttribute("exception", throwable);
         }
@@ -63,7 +63,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         req.setAttribute("message", getMessage());
         if (pre)
             req.setAttribute("pre", true);
diff --git a/core/src/main/java/hudson/model/FileParameterDefinition.java b/core/src/main/java/hudson/model/FileParameterDefinition.java
index 25cb08336da3..b8332f5911c5 100644
--- a/core/src/main/java/hudson/model/FileParameterDefinition.java
+++ b/core/src/main/java/hudson/model/FileParameterDefinition.java
@@ -29,17 +29,17 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.Extension;
 import hudson.cli.CLICommand;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.util.Objects;
-import javax.servlet.ServletException;
 import net.sf.json.JSONObject;
 import org.apache.commons.fileupload2.core.FileItem;
 import org.apache.commons.io.FileUtils;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link ParameterDefinition} for doing file upload.
@@ -65,7 +65,7 @@ public FileParameterDefinition(@NonNull String name, @CheckForNull String descri
     }
 
     @Override
-    public FileParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public FileParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         FileParameterValue p = req.bindJSON(FileParameterValue.class, jo);
         p.setLocation(getName());
         p.setDescription(getDescription());
@@ -87,7 +87,7 @@ public String getHelpFile() {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req) {
+    public ParameterValue createValue(StaplerRequest2 req) {
         FileItem src;
         try {
             src = req.getFileItem2(getName());
diff --git a/core/src/main/java/hudson/model/FileParameterValue.java b/core/src/main/java/hudson/model/FileParameterValue.java
index 343e30bb64f4..abeb1f41816a 100644
--- a/core/src/main/java/hudson/model/FileParameterValue.java
+++ b/core/src/main/java/hudson/model/FileParameterValue.java
@@ -50,8 +50,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link ParameterValue} for {@link FileParameterDefinition}.
@@ -235,9 +235,9 @@ public String toString() {
     }
 
     /**
-     * Serve this file parameter in response to a {@link StaplerRequest}.
+     * Serve this file parameter in response to a {@link StaplerRequest2}.
      */
-    public DirectoryBrowserSupport doDynamic(StaplerRequest request, StaplerResponse response) {
+    public DirectoryBrowserSupport doDynamic(StaplerRequest2 request, StaplerResponse2 response) {
         AbstractBuild build = (AbstractBuild) request.findAncestor(AbstractBuild.class).getObject();
         File fileParameter = getFileParameterFolderUnderBuild(build);
         return new DirectoryBrowserSupport(build, new FilePath(fileParameter), Messages.FileParameterValue_IndexTitle(), "folder.png", false);
diff --git a/core/src/main/java/hudson/model/Hudson.java b/core/src/main/java/hudson/model/Hudson.java
index 784fa47da20e..7d45fd63d749 100644
--- a/core/src/main/java/hudson/model/Hudson.java
+++ b/core/src/main/java/hudson/model/Hudson.java
@@ -38,14 +38,16 @@
 import hudson.slaves.ComputerListener;
 import hudson.util.CopyOnWriteList;
 import hudson.util.FormValidation;
+import io.jenkins.servlet.ServletContextWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.text.NumberFormat;
 import java.text.ParseException;
 import java.util.List;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.jvnet.hudson.reactor.ReactorException;
 import org.kohsuke.stapler.QueryParameter;
@@ -78,14 +80,36 @@ public static Hudson getInstance() {
         return (Hudson) Jenkins.get();
     }
 
+    /**
+     * @since TODO
+     */
     public Hudson(File root, ServletContext context) throws IOException, InterruptedException, ReactorException {
         this(root, context, null);
     }
 
+    /**
+     * @deprecated use {@link #Hudson(File, ServletContext)}
+     */
+    @Deprecated
+    public Hudson(File root, javax.servlet.ServletContext context) throws IOException, InterruptedException, ReactorException {
+        this(root, ServletContextWrapper.toJakartaServletContext(context));
+    }
+
+    /**
+     * @since TODO
+     */
     public Hudson(File root, ServletContext context, PluginManager pluginManager) throws IOException, InterruptedException, ReactorException {
         super(root, context, pluginManager);
     }
 
+    /**
+     * @deprecated use {@link #Hudson(File, ServletContext, PluginManager)}
+     */
+    @Deprecated
+    public Hudson(File root, javax.servlet.ServletContext context, PluginManager pluginManager) throws IOException, InterruptedException, ReactorException {
+        this(root, ServletContextWrapper.toJakartaServletContext(context), pluginManager);
+    }
+
     /**
      * Gets all the installed {@link ItemListener}s.
      *
@@ -173,8 +197,12 @@ public TopLevelItem getJobCaseInsensitive(String name) {
      */
     @Deprecated
     @RequirePOST
-    public synchronized void doQuietDown(StaplerResponse rsp) throws IOException, ServletException {
-        doQuietDown().generateResponse(null, rsp, this);
+    public synchronized void doQuietDown(StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doQuietDown().generateResponse(null, StaplerResponse.toStaplerResponse2(rsp), this);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
     /**
@@ -184,7 +212,7 @@ public synchronized void doQuietDown(StaplerResponse rsp) throws IOException, Se
      *   As on 1.267, moved to "/log/rss..."
      */
     @Deprecated
-    public void doLogRss(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doLogRss(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
         String qs = req.getQueryString();
         rsp.sendRedirect2("./log/rss" + (qs == null ? "" : '?' + qs));
     }
@@ -194,7 +222,7 @@ public void doLogRss(StaplerRequest req, StaplerResponse rsp) throws IOException
      *      Define your own check method, instead of relying on this generic one.
      */
     @Deprecated
-    public void doFieldCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doFieldCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
         doFieldCheck(
                 fixEmpty(req.getParameter("value")),
                 fixEmpty(req.getParameter("type")),
diff --git a/core/src/main/java/hudson/model/Item.java b/core/src/main/java/hudson/model/Item.java
index a57011579b15..838f4e6f75a7 100644
--- a/core/src/main/java/hudson/model/Item.java
+++ b/core/src/main/java/hudson/model/Item.java
@@ -41,7 +41,7 @@
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import jenkins.util.io.OnMaster;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Basic configuration unit in Hudson.
@@ -183,7 +183,7 @@ default String getRelativeNameFrom(@NonNull Item item)  {
 
     /**
      * Returns the absolute URL of this item. This relies on the current
-     * {@link StaplerRequest} to figure out what the host name is,
+     * {@link StaplerRequest2} to figure out what the host name is,
      * so can be used only during processing client requests.
      *
      * @return
diff --git a/core/src/main/java/hudson/model/ItemGroupMixIn.java b/core/src/main/java/hudson/model/ItemGroupMixIn.java
index faa214dee621..62a46f395247 100644
--- a/core/src/main/java/hudson/model/ItemGroupMixIn.java
+++ b/core/src/main/java/hudson/model/ItemGroupMixIn.java
@@ -32,6 +32,9 @@
 import hudson.util.CopyOnWriteMap;
 import hudson.util.Function1;
 import hudson.util.Secret;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -42,8 +45,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Matcher;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
@@ -51,7 +52,9 @@
 import jenkins.security.NotReallyRoleSensitiveCallable;
 import jenkins.util.xml.XMLUtils;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.access.AccessDeniedException;
 import org.xml.sax.SAXException;
 
@@ -140,8 +143,10 @@ public static <K, V extends Item> Map<K, V> loadChildren(ItemGroup parent, File
     /**
      * Creates a {@link TopLevelItem} for example from the submission of the {@code /lib/hudson/newFromList/form} tag
      * or throws an exception if it fails.
+     *
+     * @since TODO
      */
-    public synchronized TopLevelItem createTopLevelItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized TopLevelItem createTopLevelItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         acl.checkPermission(Item.CREATE);
 
         TopLevelItem result;
@@ -206,10 +211,22 @@ public synchronized TopLevelItem createTopLevelItem(StaplerRequest req, StaplerR
         return result;
     }
 
+    /**
+     * @deprecated use {@link #createTopLevelItem(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    public synchronized TopLevelItem createTopLevelItem(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            return createTopLevelItem(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Computes the redirection target URL for the newly created {@link TopLevelItem}.
      */
-    protected String redirectAfterCreateItem(StaplerRequest req, TopLevelItem result) throws IOException {
+    protected String redirectAfterCreateItem(StaplerRequest2 req, TopLevelItem result) throws IOException {
         return req.getContextPath() + '/' + result.getUrl() + "configure";
     }
 
diff --git a/core/src/main/java/hudson/model/Job.java b/core/src/main/java/hudson/model/Job.java
index 4bd28ff2e325..10637d666d68 100644
--- a/core/src/main/java/hudson/model/Job.java
+++ b/core/src/main/java/hudson/model/Job.java
@@ -24,8 +24,8 @@
 
 package hudson.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
+import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static jakarta.servlet.http.HttpServletResponse.SC_NO_CONTENT;
 
 import com.infradna.tool.bridge_method_injector.WithBridgeMethods;
 import edu.umd.cs.findbugs.annotations.CheckForNull;
@@ -69,6 +69,8 @@
 import hudson.widgets.HistoryWidget;
 import hudson.widgets.HistoryWidget.Adapter;
 import hudson.widgets.Widget;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.awt.Color;
 import java.awt.Paint;
 import java.io.File;
@@ -85,7 +87,6 @@
 import java.util.SortedMap;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.BuildDiscarder;
 import jenkins.model.BuildDiscarderProperty;
 import jenkins.model.DirectlyModifiableTopLevelItemGroup;
@@ -98,6 +99,7 @@
 import jenkins.model.lazy.LazyBuildMixIn;
 import jenkins.scm.RunWithSCM;
 import jenkins.security.HexStringConfidentialKey;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.triggers.SCMTriggerItem;
 import jenkins.widgets.HasWidgets;
 import net.sf.json.JSONException;
@@ -122,7 +124,9 @@
 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.stapler.StaplerOverridable;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
@@ -854,9 +858,43 @@ public RunT getNearestOldBuild(int n) {
         return m.get(m.firstKey());
     }
 
+    /**
+     * @since TODO
+     */
+    @Override
+    public Object getDynamic(String token, StaplerRequest2 req,
+                             StaplerResponse2 rsp) {
+        if (Util.isOverridden(Job.class, getClass(), "getDynamic", String.class, StaplerRequest.class, StaplerResponse.class)) {
+            return getDynamic(token, StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        }
+        try {
+            // try to interpret the token as build number
+            return getBuildByNumber(Integer.parseInt(token));
+        } catch (NumberFormatException e) {
+            // try to map that to widgets
+            for (Widget w : getWidgets()) {
+                if (w.getUrlName().equals(token))
+                    return w;
+            }
+
+            // is this a permalink?
+            for (Permalink p : getPermalinks()) {
+                if (p.getId().equals(token))
+                    return p.resolve(this);
+            }
+
+            return super.getDynamic(token, req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #getDynamic(String, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     @Override
     public Object getDynamic(String token, StaplerRequest req,
             StaplerResponse rsp) {
+        // Intentionally not factoring this out into a common implementation method because it contains a call to super.
         try {
             // try to interpret the token as build number
             return getBuildByNumber(Integer.parseInt(token));
@@ -1092,7 +1130,7 @@ public PermalinkList getPermalinks() {
      *
      * @since 2.60
      */
-    public void doRssChangelog(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssChangelog(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         class FeedItem {
             ChangeLogSet.Entry e;
             int idx;
@@ -1168,8 +1206,29 @@ public String getEntryAuthor(FeedItem entry) {
     }
 
 
+    /**
+     * @since TODO
+     */
+    @Override
+    public ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
+        if (Util.isOverridden(Job.class, getClass(), "doChildrenContextMenu", StaplerRequest.class, StaplerResponse.class)) {
+            return doChildrenContextMenu(StaplerRequest.fromStaplerRequest2(request), StaplerResponse.fromStaplerResponse2(response));
+        } else {
+            return doChildrenContextMenuImpl(request, response);
+        }
+    }
 
-    @Override public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    /**
+     * @deprecated use {@link #doChildrenContextMenu(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    @Override
+    public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+        return doChildrenContextMenuImpl(StaplerRequest.toStaplerRequest2(request), StaplerResponse.toStaplerResponse2(response));
+    }
+
+    private ContextMenu doChildrenContextMenuImpl(StaplerRequest2 request, StaplerResponse2 response) {
         // not sure what would be really useful here. This needs more thoughts.
         // for the time being, I'm starting with permalinks
         ContextMenu menu = new ContextMenu();
@@ -1327,8 +1386,8 @@ private HealthReport getBuildStabilityHealthReport() {
      * Accepts submission from the configuration page.
      */
     @POST
-    public synchronized void doConfigSubmit(StaplerRequest req,
-            StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public synchronized void doConfigSubmit(StaplerRequest2 req,
+            StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         checkPermission(CONFIGURE);
 
         description = req.getParameter("description");
@@ -1373,15 +1432,32 @@ public synchronized void doConfigSubmit(StaplerRequest req,
     /**
      * Derived class can override this to perform additional config submission
      * work.
+     *
+     * @since TODO
      */
-    protected void submit(StaplerRequest req, StaplerResponse rsp)
+    protected void submit(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException, FormException {
+        if (Util.isOverridden(Job.class, getClass(), "submit", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    protected void submit(StaplerRequest req, StaplerResponse rsp)
+            throws IOException, javax.servlet.ServletException, FormException {
     }
 
     /**
      * Accepts and serves the job description
      */
-    public void doDescription(StaplerRequest req, StaplerResponse rsp)
+    public void doDescription(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException {
         if (req.getMethod().equals("GET")) {
             //read
@@ -1407,7 +1483,7 @@ public void doDescription(StaplerRequest req, StaplerResponse rsp)
     /**
      * Returns the image that shows the current buildCommand status.
      */
-    public void doBuildStatus(StaplerRequest req, StaplerResponse rsp)
+    public void doBuildStatus(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException {
         rsp.sendRedirect2(req.getContextPath() + "/images/48x48/" + getBuildStatusUrl());
     }
@@ -1577,7 +1653,7 @@ private Calendar getLastBuildTime() {
     @RequirePOST
     public/* not synchronized. see renameTo() */void doDoRename(
             StaplerRequest req, StaplerResponse rsp) throws IOException,
-            ServletException {
+            javax.servlet.ServletException {
         String newName = req.getParameter("newName");
         doConfirmRename(newName).generateResponse(req, rsp, null);
     }
@@ -1589,12 +1665,12 @@ protected void checkRename(String newName) throws Failure {
         }
     }
 
-    public void doRssAll(StaplerRequest req, StaplerResponse rsp)
+    public void doRssAll(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (all builds)", getUrl(), getBuilds().newBuilds());
     }
 
-    public void doRssFailed(StaplerRequest req, StaplerResponse rsp)
+    public void doRssFailed(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (failed builds)", getUrl(), getBuilds().failureOnly().newBuilds());
     }
diff --git a/core/src/main/java/hudson/model/JobProperty.java b/core/src/main/java/hudson/model/JobProperty.java
index 14ff87591fe9..70ef159547c0 100644
--- a/core/src/main/java/hudson/model/JobProperty.java
+++ b/core/src/main/java/hudson/model/JobProperty.java
@@ -27,6 +27,7 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.ExtensionPoint;
 import hudson.Launcher;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
 import hudson.model.queue.SubTask;
 import hudson.tasks.BuildStep;
@@ -41,6 +42,7 @@
 import jenkins.model.OptionalJobProperty;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.ExportedBean;
 
 /**
@@ -183,8 +185,28 @@ public Collection<?> getJobOverrides() {
         return Collections.emptyList();
     }
 
+    /**
+     * @since TODO
+     */
+    @Override
+    public JobProperty<?> reconfigure(StaplerRequest2 req, JSONObject form) throws FormException {
+        if (Util.isOverridden(JobProperty.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #reconfigure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
     @Override
     public JobProperty<?> reconfigure(StaplerRequest req, JSONObject form) throws FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private JobProperty<?> reconfigureImpl(StaplerRequest2 req, JSONObject form) throws FormException {
         return form == null ? null : getDescriptor().newInstance(req, form);
     }
 
diff --git a/core/src/main/java/hudson/model/JobPropertyDescriptor.java b/core/src/main/java/hudson/model/JobPropertyDescriptor.java
index 1f1c3aa7e6f0..eb9b990b7056 100644
--- a/core/src/main/java/hudson/model/JobPropertyDescriptor.java
+++ b/core/src/main/java/hudson/model/JobPropertyDescriptor.java
@@ -24,6 +24,7 @@
 
 package hudson.model;
 
+import hudson.Util;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
@@ -34,6 +35,7 @@
 import net.sf.json.JSONObject;
 import org.jvnet.tiger_types.Types;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link Descriptor} for {@link JobProperty}.
@@ -61,6 +63,23 @@ protected JobPropertyDescriptor() {
      *      null to avoid setting an instance of {@link JobProperty} to the target project (or just use {@link OptionalJobProperty})
      */
     @Override
+    public JobProperty<?> newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
+        if (Util.isOverridden(JobPropertyDescriptor.class, getClass(), "newInstance", StaplerRequest.class, JSONObject.class)) {
+            return newInstance(req != null ? StaplerRequest.fromStaplerRequest2(req) : null, formData);
+        } else {
+            // JobPropertyDescriptors are bit different in that we allow them even without any user-visible configuration parameter,
+            // so replace the lack of form data by an empty one.
+            if (formData.isNullObject()) formData = new JSONObject();
+
+            return super.newInstance(req, formData);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #newInstance(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
+    @Override
     public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {
         // JobPropertyDescriptors are bit different in that we allow them even without any user-visible configuration parameter,
         // so replace the lack of form data by an empty one.
diff --git a/core/src/main/java/hudson/model/Label.java b/core/src/main/java/hudson/model/Label.java
index 88661c6df690..53c51db9cc4b 100644
--- a/core/src/main/java/hudson/model/Label.java
+++ b/core/src/main/java/hudson/model/Label.java
@@ -71,8 +71,8 @@
 import org.antlr.v4.runtime.CommonTokenStream;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
@@ -548,7 +548,7 @@ public String toString() {
     }
 
     @Override
-    public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ContextMenu menu = new ContextMenu();
         for (Node node : getNodes()) {
             menu.add(node);
diff --git a/core/src/main/java/hudson/model/ListView.java b/core/src/main/java/hudson/model/ListView.java
index d8f6a8d48bcb..a2e25f1f1d1b 100644
--- a/core/src/main/java/hudson/model/ListView.java
+++ b/core/src/main/java/hudson/model/ListView.java
@@ -41,6 +41,8 @@
 import hudson.views.ListViewColumn;
 import hudson.views.StatusFilter;
 import hudson.views.ViewJobFilter;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -55,7 +57,6 @@
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.jcip.annotations.GuardedBy;
 import net.sf.json.JSONObject;
@@ -67,7 +68,8 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
 import org.springframework.security.access.AccessDeniedException;
@@ -97,7 +99,7 @@ public class ListView extends View implements DirectlyModifiableView {
     /**
      * Whether to recurse in ItemGroups
      */
-    private boolean recurse;
+    private volatile boolean recurse;
 
     /**
      * Compiled include pattern from the includeRegex string.
@@ -357,7 +359,7 @@ public boolean isAddToCurrentView() {
         }
     }
 
-    private boolean needToAddToCurrentView(StaplerRequest req) throws ServletException {
+    private boolean needToAddToCurrentView(StaplerRequest2 req) throws ServletException {
         String json = req.getParameter("json");
         if (json != null && !json.isEmpty()) {
             // Submitted via UI
@@ -371,7 +373,7 @@ private boolean needToAddToCurrentView(StaplerRequest req) throws ServletExcepti
 
     @Override
     @POST
-    public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         ItemGroup<? extends TopLevelItem> ig = getOwner().getItemGroup();
         if (ig instanceof ModifiableItemGroup) {
             TopLevelItem item = ((ModifiableItemGroup<? extends TopLevelItem>) ig).doCreateItem(req, rsp);
@@ -439,7 +441,32 @@ public HttpResponse doRemoveJobFromView(@QueryParameter String name) throws IOEx
      * Load view-specific properties here.
      */
     @Override
-    protected void submit(StaplerRequest req) throws ServletException, FormException, IOException {
+    protected void submit(StaplerRequest2 req) throws ServletException, FormException, IOException {
+        if (Util.isOverridden(View.class, getClass(), "submit", StaplerRequest.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            submitImpl(req);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2)}
+     */
+    @Deprecated
+    @Override
+    protected void submit(StaplerRequest req) throws javax.servlet.ServletException, FormException, IOException {
+        try {
+            submitImpl(StaplerRequest.toStaplerRequest2(req));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void submitImpl(StaplerRequest2 req) throws ServletException, FormException, IOException {
         JSONObject json = req.getSubmittedForm();
         synchronized (this) {
             recurse = json.optBoolean("recurse", true);
diff --git a/core/src/main/java/hudson/model/ManageJenkinsAction.java b/core/src/main/java/hudson/model/ManageJenkinsAction.java
index c6c37a57662a..776b37c4f265 100644
--- a/core/src/main/java/hudson/model/ManageJenkinsAction.java
+++ b/core/src/main/java/hudson/model/ManageJenkinsAction.java
@@ -36,8 +36,8 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerFallback;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Adds the "Manage Jenkins" link to the top page.
@@ -70,7 +70,7 @@ public Object getStaplerFallback() {
     }
 
     @Override
-    public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws JellyException, IOException {
+    public ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws JellyException, IOException {
         return new ContextMenu().from(this, request, response, "index");
     }
 
@@ -80,7 +80,7 @@ public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse respons
      */
     @Restricted(NoExternalUse.class)
     public void addContextMenuItem(ContextMenu menu, String url, String icon, String iconXml, String text, boolean post, boolean requiresConfirmation, Badge badge, String message) {
-        if (Stapler.getCurrentRequest().findAncestorObject(this.getClass()) != null || !Util.isSafeToRedirectTo(url)) {
+        if (Stapler.getCurrentRequest2().findAncestorObject(this.getClass()) != null || !Util.isSafeToRedirectTo(url)) {
             // Default behavior if the URL is absolute or scheme-relative, or the current object is an ancestor (i.e. would resolve correctly)
             menu.add(url, icon, iconXml, text, post, requiresConfirmation, badge, message);
             return;
diff --git a/core/src/main/java/hudson/model/ModifiableItemGroup.java b/core/src/main/java/hudson/model/ModifiableItemGroup.java
index 726a0455dc74..35e41305afb5 100644
--- a/core/src/main/java/hudson/model/ModifiableItemGroup.java
+++ b/core/src/main/java/hudson/model/ModifiableItemGroup.java
@@ -24,10 +24,15 @@
 
 package hudson.model;
 
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
+import jenkins.security.stapler.StaplerNotDispatchable;
+import org.kohsuke.stapler.ReflectionUtils;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link ItemGroup} that is a general purpose container, which allows users and the rest of the program
@@ -45,5 +50,45 @@ public interface ModifiableItemGroup<T extends Item> extends ItemGroup<T> {
      * The request format follows that of {@code &lt;n:form xmlns:n="/lib/form">}.
      *
      */
-    T doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException;
+    @StaplerNotDispatchable
+    default T doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (ReflectionUtils.isOverridden(
+                ModifiableItemGroup.class,
+                getClass(),
+                "doCreateItem",
+                StaplerRequest.class,
+                StaplerResponse.class)) {
+            try {
+                return doCreateItem(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModifiableItemGroup.class.getSimpleName() + ".doCreateItem methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doCreateItem(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    default T doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        if (ReflectionUtils.isOverridden(
+                ModifiableItemGroup.class,
+                getClass(),
+                "doCreateItem",
+                StaplerRequest2.class,
+                StaplerResponse2.class)) {
+            try {
+                return doCreateItem(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModifiableItemGroup.class.getSimpleName() + ".doCreateItem methods");
+        }
+    }
 }
diff --git a/core/src/main/java/hudson/model/MultiStageTimeSeries.java b/core/src/main/java/hudson/model/MultiStageTimeSeries.java
index ea9d25a043c0..84963cde928f 100644
--- a/core/src/main/java/hudson/model/MultiStageTimeSeries.java
+++ b/core/src/main/java/hudson/model/MultiStageTimeSeries.java
@@ -26,6 +26,7 @@
 
 import hudson.util.ChartUtil;
 import hudson.util.NoOverlapCategoryAxis;
+import jakarta.servlet.ServletException;
 import java.awt.BasicStroke;
 import java.awt.Color;
 import java.awt.Font;
@@ -39,7 +40,6 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.CategoryAxis;
@@ -53,7 +53,9 @@
 import org.jvnet.localizer.Localizable;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
@@ -298,8 +300,8 @@ protected void configurePlot(CategoryPlot plot) {
          * Renders this object as an image.
          */
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
-            ChartUtil.generateGraph(req, rsp, createChart(), 500, 400);
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
+            ChartUtil.generateGraph(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp), createChart(), 500, 400);
         }
     }
 
diff --git a/core/src/main/java/hudson/model/MyView.java b/core/src/main/java/hudson/model/MyView.java
index bc98d9a55f7f..93c9967e0e86 100644
--- a/core/src/main/java/hudson/model/MyView.java
+++ b/core/src/main/java/hudson/model/MyView.java
@@ -26,18 +26,21 @@
 
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Extension;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -64,7 +67,7 @@ public boolean contains(TopLevelItem item) {
 
     @RequirePOST
     @Override
-    public TopLevelItem doCreateItem(StaplerRequest req, StaplerResponse rsp)
+    public TopLevelItem doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException {
         ItemGroup<? extends TopLevelItem> ig = getOwner().getItemGroup();
         if (ig instanceof ModifiableItemGroup) {
@@ -85,7 +88,24 @@ public String getPostConstructLandingPage() {
     }
 
     @Override
-    protected void submit(StaplerRequest req) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest2 req) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(MyView.class, getClass(), "submit", StaplerRequest.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            // noop
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2)}
+     */
+    @Deprecated
+    @Override
+    protected void submit(StaplerRequest req) throws IOException, javax.servlet.ServletException, FormException {
         // noop
     }
 
diff --git a/core/src/main/java/hudson/model/MyViewsProperty.java b/core/src/main/java/hudson/model/MyViewsProperty.java
index 49fdfac48d2d..32ef03f73ecd 100644
--- a/core/src/main/java/hudson/model/MyViewsProperty.java
+++ b/core/src/main/java/hudson/model/MyViewsProperty.java
@@ -35,13 +35,13 @@
 import hudson.util.FormValidation;
 import hudson.views.MyViewsTabBar;
 import hudson.views.ViewsTabBar;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.text.ParseException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import net.sf.json.JSONObject;
@@ -54,8 +54,8 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerFallback;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 /**
@@ -196,7 +196,7 @@ public HttpResponse doIndex() {
     }
 
     @POST
-    public synchronized void doCreateView(StaplerRequest req, StaplerResponse rsp)
+    public synchronized void doCreateView(StaplerRequest2 req, StaplerResponse2 rsp)
             throws IOException, ServletException, ParseException, FormException {
         checkPermission(View.CREATE);
         addView(View.create(req, rsp, this));
@@ -276,7 +276,7 @@ public UserProperty newInstance(User user) {
     }
 
     @Override
-    public UserProperty reconfigure(StaplerRequest req, JSONObject form) throws FormException {
+    public UserProperty reconfigure(StaplerRequest2 req, JSONObject form) throws FormException {
         req.bindJSON(this, form);
         return this;
     }
diff --git a/core/src/main/java/hudson/model/Node.java b/core/src/main/java/hudson/model/Node.java
index 8ba16e77d4d3..55cacd269133 100644
--- a/core/src/main/java/hudson/model/Node.java
+++ b/core/src/main/java/hudson/model/Node.java
@@ -79,6 +79,7 @@
 import org.kohsuke.stapler.BindInterceptor;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.springframework.security.core.Authentication;
@@ -560,8 +561,25 @@ public ACL getACL() {
         return Jenkins.get().getAuthorizationStrategy().getACL(this);
     }
 
+    @Override
+    public Node reconfigure(@NonNull final StaplerRequest2 req, JSONObject form) throws FormException {
+        if (Util.isOverridden(Node.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #reconfigure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
     @Override
     public Node reconfigure(@NonNull final StaplerRequest req, JSONObject form) throws FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private Node reconfigureImpl(@NonNull final StaplerRequest2 req, JSONObject form) throws FormException {
         if (form == null)     return null;
 
         final JSONObject jsonForProperties = form.optJSONObject("nodeProperties");
diff --git a/core/src/main/java/hudson/model/PaneStatusProperties.java b/core/src/main/java/hudson/model/PaneStatusProperties.java
index 4807020ca714..12cb0003d671 100644
--- a/core/src/main/java/hudson/model/PaneStatusProperties.java
+++ b/core/src/main/java/hudson/model/PaneStatusProperties.java
@@ -6,8 +6,8 @@
 import hudson.Extension;
 import hudson.model.userproperty.UserPropertyCategory;
 import hudson.util.PersistedList;
+import jakarta.servlet.http.HttpSession;
 import java.io.IOException;
-import javax.servlet.http.HttpSession;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.Stapler;
 
@@ -70,13 +70,13 @@ private static class PaneStatusPropertiesSessionFallback extends PaneStatusPrope
 
         @Override
         public boolean isCollapsed(String paneId) {
-            final HttpSession session = Stapler.getCurrentRequest().getSession();
+            final HttpSession session = Stapler.getCurrentRequest2().getSession();
             return session.getAttribute(format(attribute, paneId)) != null;
         }
 
         @Override
         public boolean toggleCollapsed(String paneId) {
-            final HttpSession session = Stapler.getCurrentRequest().getSession();
+            final HttpSession session = Stapler.getCurrentRequest2().getSession();
             final String property = format(attribute, paneId);
             final Object collapsed = session.getAttribute(property);
             if (collapsed == null) {
diff --git a/core/src/main/java/hudson/model/ParameterDefinition.java b/core/src/main/java/hudson/model/ParameterDefinition.java
index 262b632ab5a2..29653c0250f4 100644
--- a/core/src/main/java/hudson/model/ParameterDefinition.java
+++ b/core/src/main/java/hudson/model/ParameterDefinition.java
@@ -41,6 +41,7 @@
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
@@ -59,7 +60,7 @@
  * <p>
  * Three classes are used to model build parameters. First is the
  * {@link ParameterDescriptor}, which tells Hudson what kind of implementations are
- * available. From {@link ParameterDescriptor#newInstance(StaplerRequest, JSONObject)},
+ * available. From {@link ParameterDescriptor#newInstance(StaplerRequest2, JSONObject)},
  * Hudson creates {@link ParameterDefinition}s based on the job configuration.
  * For example, if the user defines two string parameters "database-type" and
  * "appserver-type", we'll get two {@link StringParameterDefinition} instances
@@ -69,7 +70,7 @@
  * When a job is configured with {@link ParameterDefinition} (or more precisely,
  * {@link ParametersDefinitionProperty}, which in turns retains {@link ParameterDefinition}s),
  * user would have to enter the values for the defined build parameters.
- * The {@link #createValue(StaplerRequest, JSONObject)} method is used to convert this
+ * The {@link #createValue(StaplerRequest2, JSONObject)} method is used to convert this
  * form submission into {@link ParameterValue} objects, which are then accessible
  * during a build.
  *
@@ -85,12 +86,12 @@
  * <h3>config.jelly</h3>
  * {@link ParameterDefinition} class uses {@code config.jelly} to contribute a form
  * fragment in the job configuration screen. Values entered there are fed back to
- * {@link ParameterDescriptor#newInstance(StaplerRequest, JSONObject)} to create {@link ParameterDefinition}s.
+ * {@link ParameterDescriptor#newInstance(StaplerRequest2, JSONObject)} to create {@link ParameterDefinition}s.
  *
  * <h3>index.jelly</h3>
  * The {@code index.jelly} view contributes a form fragment in the page where the user
  * enters actual values of parameters for a build. The result of this form submission
- * is then fed to {@link ParameterDefinition#createValue(StaplerRequest, JSONObject)} to
+ * is then fed to {@link ParameterDefinition#createValue(StaplerRequest2, JSONObject)} to
  * create {@link ParameterValue}s.
  *
  * @see StringParameterDefinition
@@ -183,14 +184,37 @@ public ParameterDescriptor getDescriptor() {
      * and submits it to the server.
      */
     @CheckForNull
-    public abstract ParameterValue createValue(StaplerRequest req, JSONObject jo);
+    public /* abstract */ ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
+        return Util.ifOverridden(
+                () -> createValue(StaplerRequest.fromStaplerRequest2(req), jo),
+                ParameterDefinition.class,
+                getClass(),
+                "createValue",
+                StaplerRequest.class,
+                JSONObject.class);
+    }
+
+    /**
+     * @deprecated use {@link #createValue(StaplerRequest2, JSONObject)}
+     */
+    @CheckForNull
+    @Deprecated
+    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+        return Util.ifOverridden(
+                () -> createValue(StaplerRequest.toStaplerRequest2(req), jo),
+                ParameterDefinition.class,
+                getClass(),
+                "createValue",
+                StaplerRequest2.class,
+                JSONObject.class);
+    }
 
     /**
      * Create a parameter value from a GET with query string.
      * If no value is available in the request, it returns a default value if possible, or null.
      *
      * <p>
-     * Unlike {@link #createValue(StaplerRequest, JSONObject)}, this method is intended to support
+     * Unlike {@link #createValue(StaplerRequest2, JSONObject)}, this method is intended to support
      * the programmatic POST-ing of the build URL. This form is less expressive (as it doesn't support
      * the tree form), but it's more scriptable.
      *
@@ -202,8 +226,28 @@ public ParameterDescriptor getDescriptor() {
      *      If the parameter is deemed required but was missing in the submission.
      */
     @CheckForNull
-    public abstract ParameterValue createValue(StaplerRequest req);
+    public /* abstract */ ParameterValue createValue(StaplerRequest2 req) {
+        return Util.ifOverridden(
+                () -> createValue(StaplerRequest.fromStaplerRequest2(req)),
+                ParameterDefinition.class,
+                getClass(),
+                "createValue",
+                StaplerRequest.class);
+    }
 
+    /**
+     * @deprecated use {@link #createValue(StaplerRequest2)}
+     */
+    @CheckForNull
+    @Deprecated
+    public ParameterValue createValue(StaplerRequest req) {
+        return Util.ifOverridden(
+                () -> createValue(StaplerRequest.toStaplerRequest2(req)),
+                ParameterDefinition.class,
+                getClass(),
+                "createValue",
+                StaplerRequest2.class);
+    }
 
     /**
      * Create a parameter value from the string given in the CLI.
diff --git a/core/src/main/java/hudson/model/ParameterValue.java b/core/src/main/java/hudson/model/ParameterValue.java
index 5da680b3bb76..2fd481446f4b 100644
--- a/core/src/main/java/hudson/model/ParameterValue.java
+++ b/core/src/main/java/hudson/model/ParameterValue.java
@@ -43,14 +43,14 @@
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
 /**
  * A value for a parameter in a build.
  *
- * Created by {@link ParameterDefinition#createValue(StaplerRequest, JSONObject)} for
+ * Created by {@link ParameterDefinition#createValue(StaplerRequest2, JSONObject)} for
  * a particular build (although this 'owner' build object is passed in for every method
  * call as a parameter so that the parameter won't have to persist it.)
  *
@@ -240,7 +240,7 @@ public VariableResolver<String> createVariableResolver(AbstractBuild<?, ?> build
      * @deprecated since 2008-09-20.
      *    parameter definition may change any time. So if you find yourself
      *    in need of accessing the information from {@link ParameterDefinition},
-     *    instead copy them in {@link ParameterDefinition#createValue(StaplerRequest, JSONObject)}
+     *    instead copy them in {@link ParameterDefinition#createValue(StaplerRequest2, JSONObject)}
      *    into {@link ParameterValue}.
      */
     @Deprecated
diff --git a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java
index 66a70047e89d..a9019e5a8f1f 100644
--- a/core/src/main/java/hudson/model/ParametersDefinitionProperty.java
+++ b/core/src/main/java/hudson/model/ParametersDefinitionProperty.java
@@ -25,8 +25,8 @@
 
 package hudson.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_CREATED;
-import static javax.servlet.http.HttpServletResponse.SC_SEE_OTHER;
+import static jakarta.servlet.http.HttpServletResponse.SC_CREATED;
+import static jakarta.servlet.http.HttpServletResponse.SC_SEE_OTHER;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -35,6 +35,8 @@
 import hudson.model.Queue.WaitingItem;
 import hudson.model.queue.ScheduleResult;
 import hudson.util.AlternativeUiTextProvider;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -43,7 +45,6 @@
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.OptionalJobProperty;
 import jenkins.model.ParameterizedJobMixIn;
@@ -56,7 +57,9 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 
@@ -133,19 +136,23 @@ public Collection<Action> getJobActions(AbstractProject<?, ?> job) {
         return (AbstractProject<?, ?>) owner;
     }
 
-    /** @deprecated use {@link #_doBuild(StaplerRequest, StaplerResponse, TimeDuration)} */
+    /** @deprecated use {@link #_doBuild(StaplerRequest2, StaplerResponse2, TimeDuration)} */
     @Deprecated
-    public void _doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
-        _doBuild(req, rsp, TimeDuration.fromString(req.getParameter("delay")));
+    public void _doBuild(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            _doBuild(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), TimeDuration.fromString(req.getParameter("delay")));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
     /**
      * Interprets the form submission and schedules a build for a parameterized job.
      *
      * <p>
-     * This method is supposed to be invoked from {@link ParameterizedJobMixIn#doBuild(StaplerRequest, StaplerResponse, TimeDuration)}.
+     * This method is supposed to be invoked from {@link ParameterizedJobMixIn#doBuild(StaplerRequest2, StaplerResponse2, TimeDuration)}.
      */
-    public void _doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
+    public void _doBuild(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
         if (delay == null)
             delay = new TimeDuration(TimeUnit.MILLISECONDS.convert(getJob().getQuietPeriod(), TimeUnit.SECONDS));
 
@@ -185,13 +192,17 @@ public void _doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter Ti
             rsp.sendRedirect(".");
     }
 
-    /** @deprecated use {@link #buildWithParameters(StaplerRequest, StaplerResponse, TimeDuration)} */
+    /** @deprecated use {@link #buildWithParameters(StaplerRequest2, StaplerResponse2, TimeDuration)} */
     @Deprecated
-    public void buildWithParameters(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
-        buildWithParameters(req, rsp, TimeDuration.fromString(req.getParameter("delay")));
+    public void buildWithParameters(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            buildWithParameters(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), TimeDuration.fromString(req.getParameter("delay")));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
     }
 
-    public void buildWithParameters(StaplerRequest req, StaplerResponse rsp, @CheckForNull TimeDuration delay) throws IOException, ServletException {
+    public void buildWithParameters(StaplerRequest2 req, StaplerResponse2 rsp, @CheckForNull TimeDuration delay) throws IOException, ServletException {
         List<ParameterValue> values = new ArrayList<>();
         for (ParameterDefinition d : parameterDefinitions) {
             ParameterValue value = d.createValue(req);
@@ -232,7 +243,7 @@ public ParameterDefinition getParameterDefinition(String name) {
     @Symbol("parameters")
     public static class DescriptorImpl extends OptionalJobPropertyDescriptor {
         @Override
-        public ParametersDefinitionProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public ParametersDefinitionProperty newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             ParametersDefinitionProperty prop = (ParametersDefinitionProperty) super.newInstance(req, formData);
             if (prop != null && prop.parameterDefinitions.isEmpty()) {
                 return null;
diff --git a/core/src/main/java/hudson/model/PasswordParameterDefinition.java b/core/src/main/java/hudson/model/PasswordParameterDefinition.java
index 8074740088f0..901f1ee66712 100644
--- a/core/src/main/java/hudson/model/PasswordParameterDefinition.java
+++ b/core/src/main/java/hudson/model/PasswordParameterDefinition.java
@@ -36,7 +36,7 @@
 import org.kohsuke.accmod.restrictions.DoNotUse;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Parameter whose value is a {@link Secret} and is hidden from the UI.
@@ -80,7 +80,7 @@ public ParameterValue createValue(String value) {
     }
 
     @Override
-    public PasswordParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public PasswordParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         PasswordParameterValue value = req.bindJSON(PasswordParameterValue.class, jo);
         if (value.getValue().getPlainText().equals(DEFAULT_VALUE)) {
             value = new PasswordParameterValue(getName(), getDefaultValue());
diff --git a/core/src/main/java/hudson/model/Project.java b/core/src/main/java/hudson/model/Project.java
index 7dc8b692d940..eb31add23938 100644
--- a/core/src/main/java/hudson/model/Project.java
+++ b/core/src/main/java/hudson/model/Project.java
@@ -40,6 +40,8 @@
 import hudson.triggers.SCMTrigger;
 import hudson.triggers.Trigger;
 import hudson.util.DescribableList;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.HashSet;
@@ -49,11 +51,12 @@
 import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.triggers.SCMTriggerItem;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Buildable software project.
@@ -223,10 +226,39 @@ public MavenInstallation inferMavenInstallation() {
 // actions
 //
 //
+
+    /**
+     * @since TODO
+     */
+    @Override
+    protected void submit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(Project.class, getClass(), "submit", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+       } else {
+            super.submit(req, rsp);
+            submitImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     @Override
-    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException, FormException {
         super.submit(req, rsp);
+        try {
+            submitImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw new javax.servlet.ServletException(e);
+        }
+    }
 
+    private void submitImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         JSONObject json = req.getSubmittedForm();
 
         getBuildWrappersList().rebuild(req, json, BuildWrappers.getFor(this));
diff --git a/core/src/main/java/hudson/model/ProxyView.java b/core/src/main/java/hudson/model/ProxyView.java
index b3d19282752c..41aa51df389e 100644
--- a/core/src/main/java/hudson/model/ProxyView.java
+++ b/core/src/main/java/hudson/model/ProxyView.java
@@ -29,9 +29,10 @@
 import hudson.Util;
 import hudson.model.Descriptor.FormException;
 import hudson.util.FormValidation;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.Collection;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
@@ -39,7 +40,8 @@
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerFallback;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -98,7 +100,32 @@ public TopLevelItem getItem(String name) {
     }
 
     @Override
-    protected void submit(StaplerRequest req) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest2 req) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(ProxyView.class, getClass(), "submit", StaplerRequest.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            submitImpl(req);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2)}
+     */
+    @Deprecated
+    @Override
+    protected void submit(StaplerRequest req) throws IOException, javax.servlet.ServletException, FormException {
+        try {
+            submitImpl(StaplerRequest.toStaplerRequest2(req));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void submitImpl(StaplerRequest2 req) throws ServletException, FormException {
         String proxiedViewName = req.getSubmittedForm().getString("proxiedViewName");
         if (Jenkins.get().getView(proxiedViewName) == null) {
             throw new FormException("Not an existing global view", "proxiedViewName");
@@ -108,7 +135,7 @@ protected void submit(StaplerRequest req) throws IOException, ServletException,
 
     @RequirePOST
     @Override
-    public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         return getProxiedView().doCreateItem(req, rsp);
     }
 
@@ -139,7 +166,7 @@ public String getDisplayName() {
         @Override
         public boolean isInstantiable() {
             // doesn't make sense to add a ProxyView to the global views
-            return !(Stapler.getCurrentRequest().findAncestorObject(ViewGroup.class) instanceof Jenkins);
+            return !(Stapler.getCurrentRequest2().findAncestorObject(ViewGroup.class) instanceof Jenkins);
         }
 
     }
diff --git a/core/src/main/java/hudson/model/Queue.java b/core/src/main/java/hudson/model/Queue.java
index 0d299fb9426d..a8d4ca08ea0d 100644
--- a/core/src/main/java/hudson/model/Queue.java
+++ b/core/src/main/java/hudson/model/Queue.java
@@ -76,6 +76,8 @@
 import hudson.util.ConsistentHash;
 import hudson.util.Futures;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
@@ -107,8 +109,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.model.queue.AsynchronousExecution;
 import jenkins.model.queue.CompositeCauseOfBlockage;
@@ -130,7 +130,7 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -2415,7 +2415,7 @@ public Api getApi() throws AccessDeniedException {
             }
         }
 
-        public HttpResponse doIndex(StaplerRequest req) {
+        public HttpResponse doIndex(StaplerRequest2 req) {
             return HttpResponses.text("Queue item exists. For details check, for example, " + req.getRequestURI() + "api/json?tree=cancelled,executable[url]");
         }
 
diff --git a/core/src/main/java/hudson/model/RSS.java b/core/src/main/java/hudson/model/RSS.java
index 19727656e729..bb41c8af10a2 100644
--- a/core/src/main/java/hudson/model/RSS.java
+++ b/core/src/main/java/hudson/model/RSS.java
@@ -26,13 +26,17 @@
 
 import hudson.FeedAdapter;
 import hudson.util.RunList;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Collection;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * RSS related code.
@@ -52,8 +56,9 @@ public final class RSS {
      *      Entries to be listed in the RSS feed.
      * @param adapter
      *      Controls how to render entries to RSS.
+     * @since TODO
      */
-    public static <E> void forwardToRss(String title, String url, Collection<? extends E> entries, FeedAdapter<E> adapter, StaplerRequest req, HttpServletResponse rsp) throws IOException, ServletException {
+    public static <E> void forwardToRss(String title, String url, Collection<? extends E> entries, FeedAdapter<E> adapter, StaplerRequest2 req, HttpServletResponse rsp) throws IOException, ServletException {
         req.setAttribute("adapter", adapter);
         req.setAttribute("title", title);
         req.setAttribute("url", url);
@@ -72,6 +77,18 @@ public static <E> void forwardToRss(String title, String url, Collection<? exten
         req.getView(Jenkins.get(), "/hudson/" + flavor + ".jelly").forward(req, rsp);
     }
 
+    /**
+     * @deprecated use {@link #forwardToRss(String, String, Collection, FeedAdapter, StaplerRequest2, HttpServletResponse)}
+     */
+    @Deprecated
+    public static <E> void forwardToRss(String title, String url, Collection<? extends E> entries, FeedAdapter<E> adapter, StaplerRequest req, javax.servlet.http.HttpServletResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            forwardToRss(title, url, entries, adapter, StaplerRequest.toStaplerRequest2(req), HttpServletResponseWrapper.toJakartaHttpServletResponse(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Sends the RSS feed to the client using a default feed adapter.
      *
@@ -81,12 +98,25 @@ public static <E> void forwardToRss(String title, String url, Collection<? exten
      *      URL of the model object that owns this feed. Relative to the context root.
      * @param runList
      *      Entries to be listed in the RSS feed.
-     * @since 2.215
+     * @since TODO
      */
-    public static void rss(StaplerRequest req, StaplerResponse rsp, String title, String url, RunList runList) throws IOException, ServletException {
+    public static void rss(StaplerRequest2 req, StaplerResponse2 rsp, String title, String url, RunList runList) throws IOException, ServletException {
         rss(req, rsp, title, url, runList, null);
     }
 
+    /**
+     * @deprecated use {@link #rss(StaplerRequest2, StaplerResponse2, String, String, RunList)}
+     * @since 2.215
+     */
+    @Deprecated
+    public static void rss(StaplerRequest req, StaplerResponse rsp, String title, String url, RunList runList) throws IOException, javax.servlet.ServletException {
+        try {
+            rss(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), title, url, runList, null);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Sends the RSS feed to the client using a specific feed adapter.
      *
@@ -98,10 +128,23 @@ public static void rss(StaplerRequest req, StaplerResponse rsp, String title, St
      *      Entries to be listed in the RSS feed.
      * @param feedAdapter
      *      Controls how to render entries to RSS.
-     * @since 2.215
+     * @since TODO
      */
-    public static void rss(StaplerRequest req, StaplerResponse rsp, String title, String url, RunList runList, FeedAdapter<Run> feedAdapter) throws IOException, ServletException {
+    public static void rss(StaplerRequest2 req, StaplerResponse2 rsp, String title, String url, RunList runList, FeedAdapter<Run> feedAdapter) throws IOException, ServletException {
         final FeedAdapter<Run> feedAdapter_ = feedAdapter == null ? Run.FEED_ADAPTER : feedAdapter;
         forwardToRss(title, url, runList, feedAdapter_, req, rsp);
     }
+
+    /**
+     * @deprecated use {@link #rss(StaplerRequest2, StaplerResponse2, String, String, RunList, FeedAdapter)}
+     * @since 2.215
+     */
+    @Deprecated
+    public static void rss(StaplerRequest req, StaplerResponse rsp, String title, String url, RunList runList, FeedAdapter<Run> feedAdapter) throws IOException, javax.servlet.ServletException {
+        try {
+            rss(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), title, url, runList, feedAdapter);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
 }
diff --git a/core/src/main/java/hudson/model/ReconfigurableDescribable.java b/core/src/main/java/hudson/model/ReconfigurableDescribable.java
index 1747fdb452c1..c044391b77ad 100644
--- a/core/src/main/java/hudson/model/ReconfigurableDescribable.java
+++ b/core/src/main/java/hudson/model/ReconfigurableDescribable.java
@@ -26,10 +26,13 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
 import hudson.slaves.NodeProperty;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Marks modern {@link Describable}s that allow the current instances to pass information down to the next
@@ -44,7 +47,7 @@
  * <strong>Invisible Property:</strong>
  * This mechanism can be used to create an entirely invisible {@link Describable}, which is handy
  * for {@link NodeProperty}, {@link JobProperty}, etc. To do so, define an empty config.jelly to prevent it from
- * showing up in the config UI, then implement {@link #reconfigure(StaplerRequest, JSONObject)}
+ * showing up in the config UI, then implement {@link #reconfigure(StaplerRequest2, JSONObject)}
  * and simply return {@code this}.
  *
  * <p>
@@ -78,5 +81,29 @@ public interface ReconfigurableDescribable<T extends ReconfigurableDescribable<T
      * @return
      *      The new instance. To not to create an instance of a describable, return null.
      */
-    @CheckForNull T reconfigure(@NonNull StaplerRequest req, @CheckForNull JSONObject form) throws FormException;
+    @CheckForNull
+    @StaplerNotDispatchable
+    default T reconfigure(@NonNull StaplerRequest2 req, @CheckForNull JSONObject form) throws FormException {
+        if (Util.isOverridden(ReconfigurableDescribable.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ReconfigurableDescribable.class.getSimpleName() + ".reconfigure methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #reconfigure(StaplerRequest2, JSONObject)}
+     */
+    @CheckForNull
+    @Deprecated
+    @StaplerNotDispatchable
+    default T reconfigure(@NonNull StaplerRequest req, @CheckForNull JSONObject form) throws FormException {
+        if (Util.isOverridden(ReconfigurableDescribable.class, getClass(), "reconfigure", StaplerRequest2.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.toStaplerRequest2(req), form);
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ReconfigurableDescribable.class.getSimpleName() + ".reconfigure methods");
+        }
+    }
 }
diff --git a/core/src/main/java/hudson/model/Run.java b/core/src/main/java/hudson/model/Run.java
index 33658252b922..c6eedc42785f 100644
--- a/core/src/main/java/hudson/model/Run.java
+++ b/core/src/main/java/hudson/model/Run.java
@@ -68,6 +68,9 @@
 import hudson.util.LogTaskListener;
 import hudson.util.ProcessTree;
 import hudson.util.XStream2;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.File;
@@ -106,8 +109,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.zip.GZIPInputStream;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.ArtifactManager;
 import jenkins.model.ArtifactManagerConfiguration;
 import jenkins.model.ArtifactManagerFactory;
@@ -119,6 +120,7 @@
 import jenkins.model.lazy.BuildReference;
 import jenkins.model.lazy.LazyBuildMixIn;
 import jenkins.security.MasterToSlaveCallable;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import jenkins.util.VirtualFile;
 import jenkins.util.io.OnMaster;
@@ -132,7 +134,9 @@
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -1043,7 +1047,7 @@ protected void dropLinks() {
         // RUN may be accessed using permalinks, as "/lastSuccessful" or other, so try to retrieve this base URL
         // looking for "this" in the current request ancestors
         // @see also {@link AbstractItem#getUrl}
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req != null) {
             String seed = Functions.getNearestAncestorUrl(req, this);
             if (seed != null) {
@@ -2157,7 +2161,7 @@ private String convertBytesToString(List<Byte> bytes) {
         return new String(byteArray, getCharset());
     }
 
-    public void doBuildStatus(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doBuildStatus(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         rsp.sendRedirect2(req.getContextPath() + "/images/48x48/" + getBuildStatusUrl());
     }
 
@@ -2260,7 +2264,7 @@ public abstract static class StatusSummarizer implements ExtensionPoint {
     /**
      * Returns the build number in the body.
      */
-    public void doBuildNumber(StaplerResponse rsp) throws IOException {
+    public void doBuildNumber(StaplerResponse2 rsp) throws IOException {
         rsp.setContentType("text/plain");
         rsp.setCharacterEncoding("US-ASCII");
         rsp.setStatus(HttpServletResponse.SC_OK);
@@ -2270,7 +2274,7 @@ public void doBuildNumber(StaplerResponse rsp) throws IOException {
     /**
      * Returns the build time stamp in the body.
      */
-    public void doBuildTimestamp(StaplerRequest req, StaplerResponse rsp, @QueryParameter String format) throws IOException {
+    public void doBuildTimestamp(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String format) throws IOException {
         rsp.setContentType("text/plain");
         rsp.setCharacterEncoding("US-ASCII");
         rsp.setStatus(HttpServletResponse.SC_OK);
@@ -2282,8 +2286,27 @@ public void doBuildTimestamp(StaplerRequest req, StaplerResponse rsp, @QueryPara
 
     /**
      * Sends out the raw console output.
+     *
+     * @since TODO
      */
+    public void doConsoleText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
+        if (Util.isOverridden(Run.class, getClass(), "doConsoleText", StaplerRequest.class, StaplerResponse.class)) {
+            doConsoleText(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            doConsoleTextImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doConsoleText(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
     public void doConsoleText(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        doConsoleTextImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doConsoleTextImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         rsp.setContentType("text/plain;charset=UTF-8");
         try (InputStream input = getLogInputStream();
              OutputStream os = rsp.getOutputStream();
@@ -2299,7 +2322,7 @@ public void doConsoleText(StaplerRequest req, StaplerResponse rsp) throws IOExce
      */
     @Deprecated
     public void doProgressiveLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
-        getLogText().doProgressText(req, rsp);
+        getLogText().doProgressText(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
     }
 
     /**
@@ -2320,7 +2343,7 @@ public boolean canToggleLogKeep() {
     }
 
     @RequirePOST
-    public void doToggleLogKeep(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doToggleLogKeep(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         keepLog(!keepLog);
         rsp.forwardToPreviousPage(req);
     }
@@ -2341,9 +2364,37 @@ public void keepLog(boolean newValue) throws IOException {
 
     /**
      * Deletes the build when the button is pressed.
+     *
+     * @since TODO
      */
     @RequirePOST
-    public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doDoDelete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Run.class, getClass(), "doDoDelete", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doDoDelete(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+            return;
+        } else {
+            doDoDeleteImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doDoDelete(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doDoDeleteImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doDoDeleteImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         checkPermission(DELETE);
 
         // We should not simply delete the build if it has been explicitly
@@ -2376,7 +2427,7 @@ public void setDescription(String description) throws IOException {
      * Accepts the new description.
      */
     @RequirePOST
-    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         setDescription(req.getParameter("description"));
         rsp.sendRedirect(".");  // go to the top page
     }
@@ -2507,7 +2558,7 @@ public long getEstimatedDuration() {
     }
 
     @POST
-    public @NonNull HttpResponse doConfigSubmit(StaplerRequest req) throws IOException, ServletException, FormException {
+    public @NonNull HttpResponse doConfigSubmit(StaplerRequest2 req) throws IOException, ServletException, FormException {
         checkPermission(UPDATE);
         try (BulkChange bc = new BulkChange(this)) {
             JSONObject json = req.getSubmittedForm();
@@ -2625,9 +2676,27 @@ public String getEntryAuthor(Run entry) {
         }
     }
 
+    @Override
+    public Object getDynamic(String token, StaplerRequest2 req, StaplerResponse2 rsp) {
+        if (Util.isOverridden(Run.class, getClass(), "getDynamic", String.class, StaplerRequest.class, StaplerResponse.class)) {
+            return getDynamic(token, StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            Object returnedResult = super.getDynamic(token, req, rsp);
+            return getDynamicImpl(token, returnedResult);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #getDynamic(String, StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
     @Override
     public Object getDynamic(String token, StaplerRequest req, StaplerResponse rsp) {
         Object returnedResult = super.getDynamic(token, req, rsp);
+        return getDynamicImpl(token, returnedResult);
+    }
+
+    private Object getDynamicImpl(String token, Object returnedResult) {
         if (returnedResult == null) {
             //check transient actions too
             for (Action action : getTransientActions()) {
@@ -2669,7 +2738,7 @@ public Object getTarget() {
 
 
     public static class RedirectUp {
-        public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             // Compromise to handle both browsers (auto-redirect) and programmatic access
             // (want accurate 404 response).. send 404 with javascript to redirect browsers.
             rsp.setStatus(HttpServletResponse.SC_NOT_FOUND);
diff --git a/core/src/main/java/hudson/model/RunParameterDefinition.java b/core/src/main/java/hudson/model/RunParameterDefinition.java
index 9aec159686b9..487d895839dd 100644
--- a/core/src/main/java/hudson/model/RunParameterDefinition.java
+++ b/core/src/main/java/hudson/model/RunParameterDefinition.java
@@ -38,7 +38,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 
 public class RunParameterDefinition extends SimpleParameterDefinition {
@@ -155,7 +155,7 @@ public String getHelpFile() {
         }
 
         @Override
-        public ParameterDefinition newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public ParameterDefinition newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             return req.bindJSON(RunParameterDefinition.class, formData);
         }
 
@@ -202,7 +202,7 @@ public ParameterValue getDefaultParameterValue() {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         RunParameterValue value = req.bindJSON(RunParameterValue.class, jo);
         value.setDescription(getDescription());
         return value;
diff --git a/core/src/main/java/hudson/model/SimpleParameterDefinition.java b/core/src/main/java/hudson/model/SimpleParameterDefinition.java
index 0be175bb4a86..f52f9a338922 100644
--- a/core/src/main/java/hudson/model/SimpleParameterDefinition.java
+++ b/core/src/main/java/hudson/model/SimpleParameterDefinition.java
@@ -5,7 +5,7 @@
 import hudson.cli.CLICommand;
 import java.io.IOException;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Convenient base class for {@link ParameterDefinition} whose value can be represented in a context-independent single string token.
@@ -31,7 +31,7 @@ protected SimpleParameterDefinition(@NonNull String name, @CheckForNull String d
     public abstract ParameterValue createValue(String value);
 
     @Override
-    public final ParameterValue createValue(StaplerRequest req) {
+    public final ParameterValue createValue(StaplerRequest2 req) {
         String[] value = req.getParameterValues(getName());
         if (value == null) {
             return getDefaultParameterValue();
diff --git a/core/src/main/java/hudson/model/Slave.java b/core/src/main/java/hudson/model/Slave.java
index 4ad75e039386..588dbf70b40d 100644
--- a/core/src/main/java/hudson/model/Slave.java
+++ b/core/src/main/java/hudson/model/Slave.java
@@ -51,6 +51,7 @@
 import hudson.util.ClockDifference;
 import hudson.util.DescribableList;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -69,7 +70,6 @@
 import java.util.jar.Manifest;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.security.MasterToSlaveCallable;
 import jenkins.slaves.WorkspaceLocator;
@@ -80,8 +80,8 @@
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Information about a Hudson agent node.
@@ -418,7 +418,7 @@ public JnlpJar(String fileName) {
             this.fileName = fileName;
         }
 
-        public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+        public void doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
             URLConnection con = connect();
             // since we end up redirecting users to jnlpJars/foo.jar/, set the content disposition
             // so that browsers can download them in the right file name.
@@ -430,7 +430,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException,
         }
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             doIndex(req, rsp);
         }
 
@@ -465,7 +465,7 @@ public URL getURL() throws IOException {
                 }
             }
 
-            URL res = Jenkins.get().servletContext.getResource("/WEB-INF/" + name);
+            URL res = Jenkins.get().getServletContext().getResource("/WEB-INF/" + name);
             if (res == null) {
                 throw new FileNotFoundException(name); // giving up
             } else {
@@ -622,7 +622,7 @@ public FormValidation doCheckNumExecutors(@QueryParameter String value) {
         /**
          * Performs syntactical check on the remote FS for agents.
          */
-        public FormValidation doCheckRemoteFS(@QueryParameter String value) throws IOException, ServletException {
+        public FormValidation doCheckRemoteFS(@QueryParameter String value) throws IOException {
             if (Util.fixEmptyAndTrim(value) == null)
                 return FormValidation.error(Messages.Slave_Remote_Director_Mandatory());
 
diff --git a/core/src/main/java/hudson/model/StockStatusIcon.java b/core/src/main/java/hudson/model/StockStatusIcon.java
index 00ce50b0453b..4fb1a9bfa007 100644
--- a/core/src/main/java/hudson/model/StockStatusIcon.java
+++ b/core/src/main/java/hudson/model/StockStatusIcon.java
@@ -29,9 +29,9 @@ public StockStatusIcon(String image, Localizable description) {
     @Override
     public String getImageOf(String size) {
         if (image.endsWith(".svg")) {
-            return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH + "/images/svgs/" + image;
+            return Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH + "/images/svgs/" + image;
         } else {
-            return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH +
+            return Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH +
                 "/images/" + size + "/" + image;
         }
     }
diff --git a/core/src/main/java/hudson/model/StringParameterDefinition.java b/core/src/main/java/hudson/model/StringParameterDefinition.java
index 8a5dfa9f1b04..160e1b1a9c0c 100644
--- a/core/src/main/java/hudson/model/StringParameterDefinition.java
+++ b/core/src/main/java/hudson/model/StringParameterDefinition.java
@@ -36,7 +36,7 @@
 import org.kohsuke.accmod.restrictions.DoNotUse;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Parameter whose value is a string value.
@@ -147,7 +147,7 @@ public String getHelpFile() {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         StringParameterValue value = req.bindJSON(StringParameterValue.class, jo);
         if (isTrim()) {
             value.doTrim();
diff --git a/core/src/main/java/hudson/model/TaskAction.java b/core/src/main/java/hudson/model/TaskAction.java
index 60ca66ac0536..e0597218f5d5 100644
--- a/core/src/main/java/hudson/model/TaskAction.java
+++ b/core/src/main/java/hudson/model/TaskAction.java
@@ -27,12 +27,12 @@
 import hudson.console.AnnotatedLargeText;
 import hudson.security.ACL;
 import hudson.security.Permission;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.lang.ref.WeakReference;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.framework.io.LargeText;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
@@ -113,7 +113,7 @@ public TaskThread getWorkerThread() {
     /**
      * Handles incremental log output.
      */
-    public void doProgressiveLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doProgressiveLog(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         AnnotatedLargeText text = obtainLog();
         if (text != null) {
             text.doProgressText(req, rsp);
@@ -125,7 +125,7 @@ public void doProgressiveLog(StaplerRequest req, StaplerResponse rsp) throws IOE
     /**
      * Handles incremental log output.
      */
-    public void doProgressiveHtml(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doProgressiveHtml(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         AnnotatedLargeText text = obtainLog();
         if (text != null) {
             text.doProgressiveHtml(req, rsp);
@@ -138,7 +138,7 @@ public void doProgressiveHtml(StaplerRequest req, StaplerResponse rsp) throws IO
      * Clears the error status.
      */
     @RequirePOST
-    public synchronized void doClearError(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doClearError(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         getACL().checkPermission(getPermission());
 
         if (workerThread != null && !workerThread.isRunning())
diff --git a/core/src/main/java/hudson/model/TextParameterDefinition.java b/core/src/main/java/hudson/model/TextParameterDefinition.java
index a22b1903e59b..96d973dc765a 100644
--- a/core/src/main/java/hudson/model/TextParameterDefinition.java
+++ b/core/src/main/java/hudson/model/TextParameterDefinition.java
@@ -32,7 +32,7 @@
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link StringParameterDefinition} that uses textarea, instead of text box.
@@ -68,7 +68,7 @@ public StringParameterValue getDefaultParameterValue() {
     }
 
     @Override
-    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+    public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
         TextParameterValue value = req.bindJSON(TextParameterValue.class, jo);
         value.setDescription(getDescription());
         return value;
diff --git a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java
index d84e4a684f22..817c1194a3d5 100644
--- a/core/src/main/java/hudson/model/TopLevelItemDescriptor.java
+++ b/core/src/main/java/hudson/model/TopLevelItemDescriptor.java
@@ -164,7 +164,7 @@ public String getDescription() {
                 DefaultScriptInvoker dsi = new DefaultScriptInvoker();
                 StringWriter sw = new StringWriter();
                 XMLOutput xml = dsi.createXMLOutput(sw, true);
-                dsi.invokeScript(Stapler.getCurrentRequest(), Stapler.getCurrentResponse(), s, this, xml);
+                dsi.invokeScript(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2(), s, this, xml);
                 return sw.toString();
             } catch (Exception e) {
                 LOGGER.log(Level.WARNING, null, e);
diff --git a/core/src/main/java/hudson/model/UpdateCenter.java b/core/src/main/java/hudson/model/UpdateCenter.java
index 4df95b7b3f45..437444feb434 100644
--- a/core/src/main/java/hudson/model/UpdateCenter.java
+++ b/core/src/main/java/hudson/model/UpdateCenter.java
@@ -58,6 +58,7 @@
 import hudson.util.PersistedList;
 import hudson.util.VersionNumber;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletException;
 import java.io.BufferedInputStream;
 import java.io.File;
 import java.io.FileInputStream;
@@ -107,7 +108,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import javax.net.ssl.SSLHandshakeException;
-import javax.servlet.ServletException;
 import jenkins.MissingDependencyException;
 import jenkins.RestartRequiredException;
 import jenkins.install.InstallUtil;
@@ -115,6 +115,7 @@
 import jenkins.model.Jenkins;
 import jenkins.model.Loadable;
 import jenkins.security.stapler.StaplerDispatchable;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import jenkins.util.Timer;
 import jenkins.util.io.OnMaster;
@@ -129,7 +130,8 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -439,7 +441,25 @@ public Badge getBadge() {
      * @return The current connection status.
      */
     @Restricted(DoNotUse.class)
+    public HttpResponse doConnectionStatus(StaplerRequest2 request) {
+        if (Util.isOverridden(UpdateCenter.class, getClass(), "doConnectionStatus", StaplerRequest.class)) {
+            return doConnectionStatus(StaplerRequest.fromStaplerRequest2(request));
+        } else {
+            return doConnectionStatusImpl(request);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doConnectionStatus(StaplerRequest2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    @Restricted(DoNotUse.class)
     public HttpResponse doConnectionStatus(StaplerRequest request) {
+        return doConnectionStatusImpl(StaplerRequest.toStaplerRequest2(request));
+    }
+
+    private HttpResponse doConnectionStatusImpl(StaplerRequest2 request) {
         Jenkins.get().checkPermission(Jenkins.SYSTEM_READ);
         try {
             String siteId = request.getParameter("siteId");
@@ -536,12 +556,12 @@ public synchronized void persistInstallStatus() {
      * <p>
      * Supports a "correlationId" request parameter if you only want to get the
      * install status of a set of plugins requested for install through
-     * {@link PluginManager#doInstallPlugins(org.kohsuke.stapler.StaplerRequest)}.
+     * {@link PluginManager#doInstallPlugins(org.kohsuke.stapler.StaplerRequest2)}.
      *
      * @return The current installation status of a plugin set.
      */
     @Restricted(DoNotUse.class)
-    public HttpResponse doInstallStatus(StaplerRequest request) {
+    public HttpResponse doInstallStatus(StaplerRequest2 request) {
         try {
             String correlationId = request.getParameter("correlationId");
             Map<String, Object> response = new HashMap<>();
@@ -754,7 +774,7 @@ private boolean checkMinVersion(@CheckForNull Plugin p, @CheckForNull VersionNum
      * Schedules a Jenkins upgrade.
      */
     @RequirePOST
-    public void doUpgrade(StaplerResponse rsp) throws IOException, ServletException {
+    public void doUpgrade(StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         HudsonUpgradeJob job = new HudsonUpgradeJob(getCoreSource(), Jenkins.getAuthentication2());
         if (!Lifecycle.get().canRewriteHudsonWar()) {
@@ -786,7 +806,7 @@ public HttpResponse doInvalidateData() {
      * Schedules a Jenkins restart.
      */
     @RequirePOST
-    public void doSafeRestart(StaplerRequest request, StaplerResponse response) throws IOException, ServletException {
+    public void doSafeRestart(StaplerRequest2 request, StaplerResponse2 response) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         synchronized (jobs) {
             if (!isRestartScheduled()) {
@@ -801,7 +821,7 @@ public void doSafeRestart(StaplerRequest request, StaplerResponse response) thro
      * Cancel all scheduled jenkins restarts
      */
     @RequirePOST
-    public void doCancelRestart(StaplerResponse response) throws IOException, ServletException {
+    public void doCancelRestart(StaplerResponse2 response) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         synchronized (jobs) {
             for (UpdateCenterJob job : jobs) {
@@ -860,7 +880,7 @@ public boolean isDowngradable() {
      * Performs hudson downgrade.
      */
     @RequirePOST
-    public void doDowngrade(StaplerResponse rsp) throws IOException, ServletException {
+    public void doDowngrade(StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         if (!isDowngradable()) {
             sendError("Jenkins downgrade is not possible, probably backup does not exist");
@@ -877,7 +897,7 @@ public void doDowngrade(StaplerResponse rsp) throws IOException, ServletExceptio
      * Performs hudson downgrade.
      */
     @RequirePOST
-    public void doRestart(StaplerResponse rsp) throws IOException, ServletException {
+    public void doRestart(StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         HudsonDowngradeJob job = new HudsonDowngradeJob(getCoreSource(), Jenkins.getAuthentication2());
         LOGGER.info("Scheduling the core downgrade");
@@ -2392,7 +2412,7 @@ private File getCached(DownloadJob job) {
                  * Could make PluginManager#getDetachedLocation public and consume it here, but this method is
                  * best-effort anyway.
                  */
-                src = Jenkins.get().servletContext.getResource(String.format("/WEB-INF/detached-plugins/%s.hpi", plugin.name));
+                src = Jenkins.get().getServletContext().getResource(String.format("/WEB-INF/detached-plugins/%s.hpi", plugin.name));
             } catch (MalformedURLException e) {
                 return null;
             }
diff --git a/core/src/main/java/hudson/model/UsageStatistics.java b/core/src/main/java/hudson/model/UsageStatistics.java
index 341f135c52f1..04d1be58209a 100644
--- a/core/src/main/java/hudson/model/UsageStatistics.java
+++ b/core/src/main/java/hudson/model/UsageStatistics.java
@@ -67,7 +67,7 @@
 import jenkins.security.FIPS140;
 import jenkins.util.SystemProperties;
 import net.sf.json.JSONObject;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -138,7 +138,7 @@ public String getStatData() throws IOException {
         JSONObject o = new JSONObject();
         o.put("stat", 1);
         o.put("install", j.getLegacyInstanceId());
-        o.put("servletContainer", j.servletContext.getServerInfo());
+        o.put("servletContainer", j.getServletContext().getServerInfo());
         o.put("version", Jenkins.VERSION);
 
         List<JSONObject> nodes = new ArrayList<>();
@@ -212,7 +212,7 @@ public Permission getRequiredGlobalConfigPagePermission() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             // for backward compatibility reasons, this configuration is stored in Jenkins
             if (DISABLED) {
diff --git a/core/src/main/java/hudson/model/User.java b/core/src/main/java/hudson/model/User.java
index 792622eb3c54..685a80e540a9 100644
--- a/core/src/main/java/hudson/model/User.java
+++ b/core/src/main/java/hudson/model/User.java
@@ -47,6 +47,8 @@
 import hudson.util.FormValidation;
 import hudson.util.RunList;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -64,8 +66,6 @@
 import java.util.function.Predicate;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.IdStrategy;
 import jenkins.model.Jenkins;
 import jenkins.model.Loadable;
@@ -79,8 +79,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -485,7 +485,7 @@ private LegitimateButUnknownUserDetails(String username) throws IllegalArgumentE
      * Accepts the new description.
      */
     @RequirePOST
-    public void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         checkPermission(Jenkins.ADMINISTER);
 
         description = req.getParameter("description");
@@ -882,7 +882,7 @@ public Api getApi() {
      * Deletes this user from Hudson.
      */
     @RequirePOST
-    public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doDoDelete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         checkPermission(Jenkins.ADMINISTER);
         if (idStrategy().equals(id, Jenkins.getAuthentication2().getName())) {
             rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Cannot delete self");
@@ -894,15 +894,15 @@ public void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOExcepti
         rsp.sendRedirect2("../..");
     }
 
-    public void doRssAll(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssAll(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (all builds)", getUrl(), getBuilds().newBuilds());
     }
 
-    public void doRssFailed(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssFailed(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (failed builds)", getUrl(), getBuilds().regressionOnly());
     }
 
-    public void doRssLatest(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssLatest(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         final List<Run> lastBuilds = new ArrayList<>();
         for (Job<?, ?> p : Jenkins.get().allItems(Job.class)) {
             for (Run<?, ?> b = p.getLastBuild(); b != null; b = b.getPreviousBuild()) {
@@ -1010,7 +1010,7 @@ public List<Action> getTransientActions() {
     }
 
     @Override
-    public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         return new ContextMenu().from(this, request, response);
     }
 
diff --git a/core/src/main/java/hudson/model/UserProperty.java b/core/src/main/java/hudson/model/UserProperty.java
index a6ebeb738b23..9813cfaba62b 100644
--- a/core/src/main/java/hudson/model/UserProperty.java
+++ b/core/src/main/java/hudson/model/UserProperty.java
@@ -27,6 +27,7 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.DescriptorExtensionList;
 import hudson.ExtensionPoint;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
 import hudson.model.userproperty.UserPropertyCategory;
 import java.util.ArrayList;
@@ -34,6 +35,7 @@
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.ExportedBean;
 
 /**
@@ -101,8 +103,22 @@ public static List<UserPropertyDescriptor> allByCategoryClass(@NonNull Class<? e
         return onlyForTheCategory;
     }
 
+    @Override
+    public UserProperty reconfigure(StaplerRequest2 req, JSONObject form) throws FormException {
+        if (Util.isOverridden(UserProperty.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    @Deprecated
     @Override
     public UserProperty reconfigure(StaplerRequest req, JSONObject form) throws FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private UserProperty reconfigureImpl(StaplerRequest2 req, JSONObject form) throws FormException {
         return form == null ? null : getDescriptor().newInstance(req, form);
     }
 }
diff --git a/core/src/main/java/hudson/model/View.java b/core/src/main/java/hudson/model/View.java
index 7b1bd98eb9ee..e807fa23de30 100644
--- a/core/src/main/java/hudson/model/View.java
+++ b/core/src/main/java/hudson/model/View.java
@@ -25,7 +25,7 @@
 
 package hudson.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
 
 import com.thoughtworks.xstream.converters.ConversionException;
 import com.thoughtworks.xstream.io.StreamException;
@@ -57,6 +57,9 @@
 import hudson.util.RunList;
 import hudson.util.XStream2;
 import hudson.views.ListViewColumn;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
@@ -80,8 +83,6 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.sax.SAXSource;
@@ -93,6 +94,7 @@
 import jenkins.model.item_category.Categories;
 import jenkins.model.item_category.Category;
 import jenkins.model.item_category.ItemCategory;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.xml.XMLUtils;
 import jenkins.widgets.HasWidgets;
 import net.sf.json.JSONObject;
@@ -108,7 +110,9 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -673,7 +677,28 @@ public SearchIndexBuilder makeSearchIndex() {
      * Accepts the new description.
      */
     @RequirePOST
-    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(View.class, getClass(), "doSubmitDescription", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doSubmitDescription(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doSubmitDescriptionImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doSubmitDescription(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        doSubmitDescriptionImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doSubmitDescriptionImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         checkPermission(CONFIGURE);
 
         description = req.getParameter("description");
@@ -684,10 +709,10 @@ public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse
     /**
      * Accepts submission from the configuration page.
      *
-     * Subtypes should override the {@link #submit(StaplerRequest)} method.
+     * Subtypes should override the {@link #submit(StaplerRequest2)} method.
      */
     @POST
-    public final synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public final synchronized void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         checkPermission(CONFIGURE);
 
         submit(req);
@@ -710,13 +735,42 @@ public final synchronized void doConfigSubmit(StaplerRequest req, StaplerRespons
      *
      * Load view-specific properties here.
      */
-    protected abstract void submit(StaplerRequest req) throws IOException, ServletException, FormException;
+    protected /* abstract */ void submit(StaplerRequest2 req) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(View.class, getClass(), "submit", StaplerRequest.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + View.class.getSimpleName() + ".submit methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2)}
+     */
+    @Deprecated
+    protected void submit(StaplerRequest req) throws IOException, javax.servlet.ServletException, FormException {
+        if (Util.isOverridden(View.class, getClass(), "submit", StaplerRequest2.class)) {
+            try {
+                submit(StaplerRequest.toStaplerRequest2(req));
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + View.class.getSimpleName() + ".submit methods");
+        }
+    }
+
 
     /**
      * Deletes this view.
      */
     @RequirePOST
-    public synchronized void doDoDelete(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doDoDelete(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         checkPermission(DELETE);
 
         owner.deleteView(this);
@@ -729,13 +783,44 @@ public synchronized void doDoDelete(StaplerRequest req, StaplerResponse rsp) thr
      * Creates a new {@link Item} in this collection.
      *
      * <p>
-     * This method should call {@link ModifiableItemGroup#doCreateItem(StaplerRequest, StaplerResponse)}
+     * This method should call {@link ModifiableItemGroup#doCreateItem(StaplerRequest2, StaplerResponse2)}
      * and then add the newly created item to this view.
      *
      * @return
      *      null if fails.
+     * @since TODO
      */
-    public abstract Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException;
+    @RequirePOST
+    public /* abstract */ Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(View.class, getClass(), "doCreateItem", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                return doCreateItem(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + View.class.getSimpleName() + ".doCreateItem methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doCreateItem(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        if (Util.isOverridden(View.class, getClass(), "doCreateItem", StaplerRequest2.class, StaplerResponse2.class)) {
+            try {
+                return doCreateItem(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + View.class.getSimpleName() + ".doCreateItem methods");
+        }
+    }
 
     /**
      * Makes sure that the given name is good as a job name.
@@ -774,7 +859,7 @@ public FormValidation doCheckJobName(@QueryParameter String value) {
      * @return A {@link Categories} entity that is shown as JSON file.
      */
     @Restricted(DoNotUse.class)
-    public Categories doItemCategories(StaplerRequest req, StaplerResponse rsp, @QueryParameter String iconStyle) throws IOException, ServletException {
+    public Categories doItemCategories(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String iconStyle) throws IOException, ServletException {
         getOwner().checkPermission(Item.CREATE);
 
         rsp.addHeader("Cache-Control", "no-cache, no-store, must-revalidate");
@@ -833,11 +918,11 @@ public Categories doItemCategories(StaplerRequest req, StaplerResponse rsp, @Que
         return categories;
     }
 
-    public void doRssAll(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssAll(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (all builds)", getUrl(), getBuilds().newBuilds());
     }
 
-    public void doRssFailed(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssFailed(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         RSS.rss(req, rsp, "Jenkins:" + getDisplayName() + " (failed builds)", getUrl(), getBuilds().failureOnly().newBuilds());
     }
 
@@ -851,7 +936,7 @@ public BuildTimelineWidget getTimeline() {
         return new BuildTimelineWidget(getBuilds());
     }
 
-    public void doRssLatest(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doRssLatest(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         List<Run> lastBuilds = new ArrayList<>();
         for (TopLevelItem item : getItems()) {
             if (item instanceof Job job) {
@@ -866,13 +951,13 @@ public void doRssLatest(StaplerRequest req, StaplerResponse rsp) throws IOExcept
      * Accepts {@code config.xml} submission, as well as serve it.
      */
     @WebMethod(name = "config.xml")
-    public HttpResponse doConfigDotXml(StaplerRequest req) throws IOException {
+    public HttpResponse doConfigDotXml(StaplerRequest2 req) throws IOException {
         if (req.getMethod().equals("GET")) {
             // read
             checkPermission(READ);
             return new HttpResponse() {
                 @Override
-                public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+                public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                     rsp.setContentType("application/xml");
                     View.this.writeXml(rsp.getOutputStream());
                 }
@@ -940,7 +1025,7 @@ public void updateByXml(Source source) throws IOException {
     }
 
     @Override
-    public ModelObjectWithContextMenu.ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ModelObjectWithContextMenu.ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ModelObjectWithContextMenu.ContextMenu m = new ModelObjectWithContextMenu.ContextMenu();
         for (TopLevelItem i : getItems())
             m.add(Functions.getRelativeLinkTo(i), Functions.getRelativeDisplayNameFrom(i, getOwner().getItemGroup()));
@@ -964,15 +1049,15 @@ public static DescriptorExtensionList<View, ViewDescriptor> all() {
 
     /**
      * Returns the {@link ViewDescriptor} instances that can be instantiated for the {@link ViewGroup} in the current
-     * {@link StaplerRequest}.
+     * {@link StaplerRequest2}.
      * <p>
-     * <strong>NOTE: Historically this method is only ever called from a {@link StaplerRequest}</strong>
-     * @return the list of instantiable {@link ViewDescriptor} instances for the current {@link StaplerRequest}
+     * <strong>NOTE: Historically this method is only ever called from a {@link StaplerRequest2}</strong>
+     * @return the list of instantiable {@link ViewDescriptor} instances for the current {@link StaplerRequest2}
      */
     @NonNull
     public static List<ViewDescriptor> allInstantiable() {
         List<ViewDescriptor> r = new ArrayList<>();
-        StaplerRequest request = Stapler.getCurrentRequest();
+        StaplerRequest2 request = Stapler.getCurrentRequest2();
         if (request == null) {
             throw new IllegalStateException("This method can only be invoked from a stapler request");
         }
@@ -1018,7 +1103,10 @@ public static Permission getItemCreatePermission() {
         return Item.CREATE;
     }
 
-    public static View create(StaplerRequest req, StaplerResponse rsp, ViewGroup owner)
+    /**
+     * @since TODO
+     */
+    public static View create(StaplerRequest2 req, StaplerResponse2 rsp, ViewGroup owner)
             throws FormException, IOException, ServletException {
         String mode = req.getParameter("mode");
 
@@ -1070,7 +1158,20 @@ public static View create(StaplerRequest req, StaplerResponse rsp, ViewGroup own
         return v;
     }
 
-    private static View copy(StaplerRequest req, ViewGroup owner, String name) throws IOException {
+    /**
+     * @deprecated use {@link #create(StaplerRequest2, StaplerResponse2, ViewGroup)}
+     */
+    @Deprecated
+    public static View create(StaplerRequest req, StaplerResponse rsp, ViewGroup owner)
+            throws FormException, IOException, javax.servlet.ServletException {
+        try {
+            return create(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), owner);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private static View copy(StaplerRequest2 req, ViewGroup owner, String name) throws IOException {
         View v;
         String from = req.getParameter("from");
         View src = owner.getView(from);
diff --git a/core/src/main/java/hudson/model/ViewDescriptor.java b/core/src/main/java/hudson/model/ViewDescriptor.java
index f38e5d846d9a..e140ac474054 100644
--- a/core/src/main/java/hudson/model/ViewDescriptor.java
+++ b/core/src/main/java/hudson/model/ViewDescriptor.java
@@ -40,7 +40,7 @@
 import org.kohsuke.stapler.AncestorInPath;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link Descriptor} for {@link View}.
@@ -108,7 +108,7 @@ public AutoCompletionCandidates doAutoCompleteCopyNewItemFrom(@QueryParameter fi
      * Possible {@link ListViewColumnDescriptor}s that can be used with this view.
      */
     public List<Descriptor<ListViewColumn>> getColumnsDescriptors() {
-        StaplerRequest request = Stapler.getCurrentRequest();
+        StaplerRequest2 request = Stapler.getCurrentRequest2();
         if (request != null) {
             View view = request.findAncestorObject(clazz);
             return view == null ? DescriptorVisibilityFilter.applyType(clazz, ListViewColumn.all())
@@ -121,7 +121,7 @@ public List<Descriptor<ListViewColumn>> getColumnsDescriptors() {
      * Possible {@link ViewJobFilter} types that can be used with this view.
      */
     public List<Descriptor<ViewJobFilter>> getJobFiltersDescriptors() {
-        StaplerRequest request = Stapler.getCurrentRequest();
+        StaplerRequest2 request = Stapler.getCurrentRequest2();
         if (request != null) {
             View view = request.findAncestorObject(clazz);
             return view == null ? DescriptorVisibilityFilter.applyType(clazz, ViewJobFilter.all())
diff --git a/core/src/main/java/hudson/model/ViewJob.java b/core/src/main/java/hudson/model/ViewJob.java
index 0da32700c1bd..055b98cafdb5 100644
--- a/core/src/main/java/hudson/model/ViewJob.java
+++ b/core/src/main/java/hudson/model/ViewJob.java
@@ -25,7 +25,10 @@
 package hudson.model;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import hudson.Util;
 import hudson.model.Descriptor.FormException;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.util.LinkedHashSet;
@@ -34,11 +37,12 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link Job} that monitors activities that happen outside Hudson,
@@ -165,8 +169,30 @@ private void _reload() {
     protected abstract void reload();
 
     @Override
-    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    protected void submit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
+        if (Util.isOverridden(ViewJob.class, getClass(), "submit", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                submit(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            super.submit(req, rsp);
+            submitImpl();
+        }
+    }
+
+    /**
+     * @deprecated use {@link #submit(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @Override
+    protected void submit(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException, FormException {
         super.submit(req, rsp);
+        submitImpl();
+    }
+
+    private void submitImpl() {
         // make sure to reload to reflect this config change.
         nextUpdate = 0;
     }
diff --git a/core/src/main/java/hudson/model/ViewProperty.java b/core/src/main/java/hudson/model/ViewProperty.java
index 31ad3078d449..15f0e62164c4 100644
--- a/core/src/main/java/hudson/model/ViewProperty.java
+++ b/core/src/main/java/hudson/model/ViewProperty.java
@@ -26,9 +26,11 @@
 
 import hudson.DescriptorExtensionList;
 import hudson.ExtensionPoint;
+import hudson.Util;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Extensible property of {@link View}.
@@ -68,8 +70,22 @@ public static DescriptorExtensionList<ViewProperty, ViewPropertyDescriptor> all(
         return Jenkins.get().getDescriptorList(ViewProperty.class);
     }
 
+    @Override
+    public ViewProperty reconfigure(StaplerRequest2 req, JSONObject form) throws Descriptor.FormException {
+        if (Util.isOverridden(ViewProperty.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    @Deprecated
     @Override
     public ViewProperty reconfigure(StaplerRequest req, JSONObject form) throws Descriptor.FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private ViewProperty reconfigureImpl(StaplerRequest2 req, JSONObject form) throws Descriptor.FormException {
         return form == null ? null : getDescriptor().newInstance(req, form);
     }
 }
diff --git a/core/src/main/java/hudson/model/labels/LabelAtom.java b/core/src/main/java/hudson/model/labels/LabelAtom.java
index 84ee083c488d..f5e597b71b30 100644
--- a/core/src/main/java/hudson/model/labels/LabelAtom.java
+++ b/core/src/main/java/hudson/model/labels/LabelAtom.java
@@ -46,6 +46,7 @@
 import hudson.util.QuotedStringTokenizer;
 import hudson.util.VariableResolver;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
@@ -56,13 +57,12 @@
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
@@ -221,7 +221,7 @@ public List<LabelAtomPropertyDescriptor> getApplicablePropertyDescriptors() {
      * Accepts the update to the node configuration.
      */
     @POST
-    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         final Jenkins app = Jenkins.get();
 
         app.checkPermission(Jenkins.ADMINISTER);
@@ -249,7 +249,7 @@ private boolean isInvalidName() {
      */
     @RequirePOST
     @Restricted(DoNotUse.class)
-    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         setDescription(req.getParameter("description"));
diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java
index 822cdc6f4c99..c0424e828419 100644
--- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java
+++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAccountAction.java
@@ -32,20 +32,20 @@
 import hudson.model.User;
 import hudson.model.UserProperty;
 import hudson.model.UserPropertyDescriptor;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.security.UserDetailsCache;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 @Restricted(NoExternalUse.class)
@@ -91,7 +91,7 @@ private static List<UserPropertyDescriptor> allByTwoCategoryClasses(
     }
 
     @POST
-    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         User targetUser = this.getTargetUser();
         targetUser.checkPermission(Jenkins.ADMINISTER);
 
diff --git a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java
index caec7c1bdf88..6eadb9f89ece 100644
--- a/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java
+++ b/core/src/main/java/hudson/model/userproperty/UserPropertyCategoryAction.java
@@ -6,14 +6,14 @@
 import hudson.model.UserProperty;
 import hudson.model.UserPropertyDescriptor;
 import hudson.util.FormApply;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 public abstract class UserPropertyCategoryAction {
@@ -31,7 +31,7 @@ public UserPropertyCategoryAction(User targetUser) {
     public @NonNull abstract List<UserPropertyDescriptor> getMyCategoryDescriptors();
 
     @POST
-    public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         this.targetUser.checkPermission(Jenkins.ADMINISTER);
 
         JSONObject json = req.getSubmittedForm();
diff --git a/core/src/main/java/hudson/scm/AbstractScmTagAction.java b/core/src/main/java/hudson/scm/AbstractScmTagAction.java
index b861a90b15fe..3bf14e753242 100644
--- a/core/src/main/java/hudson/scm/AbstractScmTagAction.java
+++ b/core/src/main/java/hudson/scm/AbstractScmTagAction.java
@@ -24,17 +24,22 @@
 
 package hudson.scm;
 
+import hudson.Util;
 import hudson.model.AbstractBuild;
 import hudson.model.BuildBadgeAction;
 import hudson.model.Run;
 import hudson.model.TaskAction;
 import hudson.security.ACL;
 import hudson.security.Permission;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import jenkins.model.RunAction2;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Common part of {@code CVSSCM.TagAction} and {@code SubversionTagAction}.
@@ -108,7 +113,32 @@ protected ACL getACL() {
         return run.getACL();
     }
 
-    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(AbstractScmTagAction.class, getClass(), "doIndex", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doIndex(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doIndexImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doIndex(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doIndexImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doIndexImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         req.getView(this, chooseAction()).forward(req, rsp);
     }
 
diff --git a/core/src/main/java/hudson/scm/RepositoryBrowsers.java b/core/src/main/java/hudson/scm/RepositoryBrowsers.java
index 0a1e28d1a152..3562f1c13964 100644
--- a/core/src/main/java/hudson/scm/RepositoryBrowsers.java
+++ b/core/src/main/java/hudson/scm/RepositoryBrowsers.java
@@ -32,6 +32,7 @@
 import java.util.List;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * List of all installed {@link RepositoryBrowsers}.
@@ -63,7 +64,7 @@ public static List<Descriptor<RepositoryBrowser<?>>> filter(Class<? extends Repo
      * Creates an instance of {@link RepositoryBrowser} from a form submission.
      *
      * @deprecated since 2008-06-19.
-     *      Use {@link #createInstance(Class, StaplerRequest, JSONObject, String)}.
+     *      Use {@link #createInstance(Class, StaplerRequest2, JSONObject, String)}.
      */
     @Deprecated
     public static <T extends RepositoryBrowser>
@@ -82,13 +83,23 @@ T createInstance(Class<T> type, StaplerRequest req, String fieldName) throws For
     /**
      * Creates an instance of {@link RepositoryBrowser} from a form submission.
      *
-     * @since 1.227
+     * @since TODO
      */
     public static <T extends RepositoryBrowser>
-    T createInstance(Class<T> type, StaplerRequest req, JSONObject parent, String fieldName) throws FormException {
+    T createInstance(Class<T> type, StaplerRequest2 req, JSONObject parent, String fieldName) throws FormException {
         JSONObject o = (JSONObject) parent.get(fieldName);
         if (o == null) return null;
 
         return req.bindJSON(type, o);
     }
+
+    /**
+     * @deprecated use {@link #createInstance(Class, StaplerRequest2, JSONObject, String)}
+     * @since 1.227
+     */
+    @Deprecated
+    public static <T extends RepositoryBrowser>
+    T createInstance(Class<T> type, StaplerRequest req, JSONObject parent, String fieldName) throws FormException {
+        return createInstance(type, StaplerRequest.toStaplerRequest2(req), parent, fieldName);
+    }
 }
diff --git a/core/src/main/java/hudson/scm/SCMS.java b/core/src/main/java/hudson/scm/SCMS.java
index a8fd4ddc4dc1..de92d453d248 100644
--- a/core/src/main/java/hudson/scm/SCMS.java
+++ b/core/src/main/java/hudson/scm/SCMS.java
@@ -28,9 +28,11 @@
 import hudson.model.AbstractProject;
 import hudson.model.Descriptor.FormException;
 import hudson.util.DescriptorList;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.util.List;
-import javax.servlet.ServletException;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * List of all installed SCMs.
@@ -53,7 +55,7 @@ public class SCMS {
      *      The project for which this SCM is configured to.
      */
     @SuppressWarnings("deprecation")
-    public static SCM parseSCM(StaplerRequest req, AbstractProject target) throws FormException, ServletException {
+    public static SCM parseSCM(StaplerRequest2 req, AbstractProject target) throws FormException, ServletException {
         SCM scm = SCM.all().newInstanceFromRadioList(req.getSubmittedForm().getJSONObject("scm"));
         if (scm == null) {
             scm = new NullSCM(); // JENKINS-36043 workaround for AbstractMultiBranchProject.submit
@@ -62,12 +64,24 @@ public static SCM parseSCM(StaplerRequest req, AbstractProject target) throws Fo
         return scm;
     }
 
+    /**
+     * @deprecated use {@link #parseSCM(StaplerRequest2, AbstractProject)}
+     */
+    @Deprecated
+    public static SCM parseSCM(StaplerRequest req, AbstractProject target) throws FormException, javax.servlet.ServletException {
+        try {
+            return parseSCM(StaplerRequest.toStaplerRequest2(req), target);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * @deprecated as of 1.294
-     *      Use {@link #parseSCM(StaplerRequest, AbstractProject)} and pass in the caller's project type.
+     *      Use {@link #parseSCM(StaplerRequest2, AbstractProject)} and pass in the caller's project type.
      */
     @Deprecated
-    public static SCM parseSCM(StaplerRequest req) throws FormException, ServletException {
+    public static SCM parseSCM(StaplerRequest req) throws FormException, javax.servlet.ServletException {
         return parseSCM(req, null);
     }
 
diff --git a/core/src/main/java/hudson/search/Search.java b/core/src/main/java/hudson/search/Search.java
index a3a674ae1106..7773d9e9d696 100644
--- a/core/src/main/java/hudson/search/Search.java
+++ b/core/src/main/java/hudson/search/Search.java
@@ -25,12 +25,14 @@
 
 package hudson.search;
 
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
+import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.Util;
 import hudson.util.EditDistance;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.AbstractList;
 import java.util.ArrayList;
@@ -40,8 +42,8 @@
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.MemoryReductionUtil;
 import jenkins.util.SystemProperties;
 import org.kohsuke.accmod.Restricted;
@@ -50,7 +52,9 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.DataWriter;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -73,7 +77,32 @@ public class Search implements StaplerProxy {
      */
     private static /* nonfinal for Jenkins script console */ int MAX_SEARCH_SIZE = Integer.getInteger(Search.class.getName() + ".MAX_SEARCH_SIZE", 500);
 
-    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(Search.class, getClass(), "doIndex", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doIndex(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doIndexImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doIndex(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doIndexImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void doIndexImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         List<Ancestor> l = req.getAncestors();
         for (int i = l.size() - 1; i >= 0; i--) {
             Ancestor a = l.get(i);
@@ -110,7 +139,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException,
      *
      * See http://developer.mozilla.org/en/docs/Supporting_search_suggestions_in_search_plugins
      */
-    public void doSuggestOpenSearch(StaplerRequest req, StaplerResponse rsp, @QueryParameter String q) throws IOException, ServletException {
+    public void doSuggestOpenSearch(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String q) throws IOException, ServletException {
         rsp.setContentType(Flavor.JSON.contentType);
         DataWriter w = Flavor.JSON.createDataWriter(null, rsp);
         w.startArray();
@@ -126,7 +155,7 @@ public void doSuggestOpenSearch(StaplerRequest req, StaplerResponse rsp, @QueryP
     /**
      * Used by search box auto-completion. Returns JSON array.
      */
-    public void doSuggest(StaplerRequest req, StaplerResponse rsp, @QueryParameter String query) throws IOException, ServletException {
+    public void doSuggest(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String query) throws IOException, ServletException {
         Result r = new Result();
         for (SuggestedItem item : getSuggestions(req, query))
             r.suggestions.add(new Item(item.getPath()));
@@ -141,7 +170,23 @@ public void doSuggest(StaplerRequest req, StaplerResponse rsp, @QueryParameter S
      *      can be empty but never null. The size of the list is always smaller than
      *      a certain threshold to avoid showing too many options.
      */
+    public SearchResult getSuggestions(StaplerRequest2 req, String query) {
+        if (Util.isOverridden(Search.class, getClass(), "getSuggestions", StaplerRequest.class, String.class)) {
+            return getSuggestions(StaplerRequest.fromStaplerRequest2(req), query);
+        } else {
+            return getSuggestionsImpl(req, query);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #getSuggestions(StaplerRequest2, String)}
+     */
+    @Deprecated
     public SearchResult getSuggestions(StaplerRequest req, String query) {
+        return getSuggestionsImpl(StaplerRequest.toStaplerRequest2(req), query);
+    }
+
+    private SearchResult getSuggestionsImpl(StaplerRequest2 req, String query) {
         Set<String> paths = new HashSet<>();  // paths already added, to control duplicates
         SearchResultImpl r = new SearchResultImpl();
         int max = Math.min(
@@ -164,7 +209,7 @@ public int getMaxSearchSize() {
         return MAX_SEARCH_SIZE;
     }
 
-    private @CheckForNull SearchableModelObject findClosestSearchableModelObject(StaplerRequest req) {
+    private @CheckForNull SearchableModelObject findClosestSearchableModelObject(StaplerRequest2 req) {
         List<Ancestor> l = req.getAncestors();
         for (int i = l.size() - 1; i >= 0; i--) {
             Ancestor a = l.get(i);
@@ -178,7 +223,7 @@ public int getMaxSearchSize() {
     /**
      * Creates merged search index for suggestion.
      */
-    private SearchIndex makeSuggestIndex(StaplerRequest req) {
+    private SearchIndex makeSuggestIndex(StaplerRequest2 req) {
         SearchIndexBuilder builder = new SearchIndexBuilder();
         for (Ancestor a : req.getAncestors()) {
             if (a.getObject() instanceof SearchableModelObject) {
diff --git a/core/src/main/java/hudson/search/UserSearchProperty.java b/core/src/main/java/hudson/search/UserSearchProperty.java
index a3515dd08874..7f36476b112b 100644
--- a/core/src/main/java/hudson/search/UserSearchProperty.java
+++ b/core/src/main/java/hudson/search/UserSearchProperty.java
@@ -8,7 +8,7 @@
 import hudson.model.userproperty.UserPropertyCategory;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 
 public class UserSearchProperty extends hudson.model.UserProperty {
@@ -51,7 +51,7 @@ public UserProperty newInstance(User user) {
         }
 
         @Override
-        public UserProperty newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public UserProperty newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             return new UserSearchProperty(formData.optBoolean("insensitiveSearch"));
         }
 
diff --git a/core/src/main/java/hudson/security/AccessDeniedException2.java b/core/src/main/java/hudson/security/AccessDeniedException2.java
index 00daee721251..e745669bad67 100644
--- a/core/src/main/java/hudson/security/AccessDeniedException2.java
+++ b/core/src/main/java/hudson/security/AccessDeniedException2.java
@@ -1,5 +1,6 @@
 package hudson.security;
 
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
 import java.io.PrintWriter;
 import javax.servlet.http.HttpServletResponse;
 import jenkins.util.SystemProperties;
@@ -42,7 +43,7 @@ public AccessDeniedException2(Throwable t, Authentication authentication, Permis
      * Reports the details of the access failure in HTTP headers to assist diagnosis.
      */
     public void reportAsHeaders(HttpServletResponse rsp) {
-        toSpring().reportAsHeaders(rsp);
+        toSpring().reportAsHeaders(HttpServletResponseWrapper.toJakartaHttpServletResponse(rsp));
     }
 
     /**
diff --git a/core/src/main/java/hudson/security/AccessDeniedException3.java b/core/src/main/java/hudson/security/AccessDeniedException3.java
index 82f5d50428ce..90fc521dfd7b 100644
--- a/core/src/main/java/hudson/security/AccessDeniedException3.java
+++ b/core/src/main/java/hudson/security/AccessDeniedException3.java
@@ -1,7 +1,8 @@
 package hudson.security;
 
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.PrintWriter;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.util.SystemProperties;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.Authentication;
@@ -43,6 +44,18 @@ public AccessDeniedException3(Throwable t, Authentication authentication, Permis
      * Reports the details of the access failure in HTTP headers to assist diagnosis.
      */
     public void reportAsHeaders(HttpServletResponse rsp) {
+        reportAsHeadersImpl(rsp);
+    }
+
+    /**
+     * @deprecated use {@link #reportAsHeaders(HttpServletResponse)}
+     */
+    @Deprecated
+    public void reportAsHeaders(javax.servlet.http.HttpServletResponse rsp) {
+        reportAsHeadersImpl(HttpServletResponseWrapper.toJakartaHttpServletResponse(rsp));
+    }
+
+    private void reportAsHeadersImpl(HttpServletResponse rsp) {
         rsp.addHeader("X-You-Are-Authenticated-As", authentication.getName());
         if (REPORT_GROUP_HEADERS) {
             for (GrantedAuthority auth : authentication.getAuthorities()) {
diff --git a/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java b/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java
index 68843cfddd16..b1f1e35e1fc8 100644
--- a/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java
+++ b/core/src/main/java/hudson/security/AccessDeniedHandlerImpl.java
@@ -24,10 +24,10 @@
 
 package hudson.security;
 
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
@@ -53,7 +53,7 @@ public void handle(HttpServletRequest req, HttpServletResponse rsp, AccessDenied
             ((AccessDeniedException3) cause).reportAsHeaders(rsp);
         }
 
-        WebApp.get(Jenkins.get().servletContext).getSomeStapler()
+        WebApp.get(Jenkins.get().getServletContext()).getSomeStapler()
                 .invoke(req, rsp, Jenkins.get(), "/accessDenied");
     }
 }
diff --git a/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java b/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java
index 2714ec8eba63..0c9559bf140f 100644
--- a/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java
+++ b/core/src/main/java/hudson/security/AuthenticationProcessingFilter2.java
@@ -26,14 +26,14 @@
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.model.User;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 import jenkins.security.SecurityListener;
 import jenkins.security.seed.UserSeedProperty;
 import jenkins.util.SystemProperties;
diff --git a/core/src/main/java/hudson/security/AuthorizationStrategy.java b/core/src/main/java/hudson/security/AuthorizationStrategy.java
index f77385829730..db3001fc40f2 100644
--- a/core/src/main/java/hudson/security/AuthorizationStrategy.java
+++ b/core/src/main/java/hudson/security/AuthorizationStrategy.java
@@ -47,7 +47,7 @@
 import jenkins.security.stapler.StaplerAccessibleType;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Controls authorization throughout Hudson.
@@ -241,7 +241,7 @@ public String getDisplayName() {
             }
 
             @Override
-            public @NonNull AuthorizationStrategy newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            public @NonNull AuthorizationStrategy newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
                 return UNSECURED;
             }
         }
diff --git a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java
index b2a06024278b..8586fb0317a0 100644
--- a/core/src/main/java/hudson/security/BasicAuthenticationFilter.java
+++ b/core/src/main/java/hudson/security/BasicAuthenticationFilter.java
@@ -27,24 +27,24 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.model.User;
 import hudson.util.Scrambler;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.security.BasicApiTokenHelper;
 import jenkins.security.SecurityListener;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.CompatibleFilter;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -68,7 +68,7 @@
  * This causes the container to perform authentication, but there's no way
  * to find out whether the user has been successfully authenticated or not.
  * So to find this out, we then redirect the user to
- * {@link jenkins.model.Jenkins#doSecured(StaplerRequest, StaplerResponse) /secured/... page}.
+ * {@link jenkins.model.Jenkins#doSecured(StaplerRequest2, StaplerResponse2) /secured/... page}.
  *
  * <p>
  * The handler of the above URL checks if the user is authenticated,
@@ -91,7 +91,7 @@
  *
  * @author Kohsuke Kawaguchi
  */
-public class BasicAuthenticationFilter implements Filter {
+public class BasicAuthenticationFilter implements CompatibleFilter {
     private ServletContext servletContext;
 
     @Override
diff --git a/core/src/main/java/hudson/security/ChainedServletFilter.java b/core/src/main/java/hudson/security/ChainedServletFilter.java
index 74e1e463f565..98bc725c2b1a 100644
--- a/core/src/main/java/hudson/security/ChainedServletFilter.java
+++ b/core/src/main/java/hudson/security/ChainedServletFilter.java
@@ -24,27 +24,28 @@
 
 package hudson.security;
 
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.regex.Pattern;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * Servlet {@link Filter} that chains multiple {@link Filter}s.
  *
  * @author Kohsuke Kawaguchi
  */
-public class ChainedServletFilter implements Filter {
+public class ChainedServletFilter implements CompatibleFilter {
     // array is assumed to be immutable once set
     protected volatile Filter[] filters;
 
diff --git a/core/src/main/java/hudson/security/ContainerAuthentication.java b/core/src/main/java/hudson/security/ContainerAuthentication.java
index be7bdc01ab62..571b5cc782e8 100644
--- a/core/src/main/java/hudson/security/ContainerAuthentication.java
+++ b/core/src/main/java/hudson/security/ContainerAuthentication.java
@@ -24,12 +24,12 @@
 
 package hudson.security;
 
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
 import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import javax.servlet.ServletRequest;
-import javax.servlet.http.HttpServletRequest;
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
diff --git a/core/src/main/java/hudson/security/FederatedLoginService.java b/core/src/main/java/hudson/security/FederatedLoginService.java
index 2d176290d8be..38d91f7da901 100644
--- a/core/src/main/java/hudson/security/FederatedLoginService.java
+++ b/core/src/main/java/hudson/security/FederatedLoginService.java
@@ -30,13 +30,13 @@
 import hudson.ExtensionPoint;
 import hudson.model.User;
 import hudson.model.UserProperty;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.io.Serializable;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
@@ -245,7 +245,7 @@ public UnclaimedIdentityException(FederatedIdentity identity) {
         }
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             SecurityRealm sr = Jenkins.get().getSecurityRealm();
             if (sr.allowsSignup()) {
                 try {
diff --git a/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java b/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
index 4c9dc1add7e7..a8657df65685 100644
--- a/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
+++ b/core/src/main/java/hudson/security/GlobalSecurityConfiguration.java
@@ -35,13 +35,13 @@
 import hudson.model.Descriptor.FormException;
 import hudson.model.ManagementLink;
 import hudson.util.FormApply;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.function.Predicate;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.GlobalConfigurationCategory;
 import jenkins.model.Jenkins;
 import jenkins.util.ServerTcpPort;
@@ -51,8 +51,8 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 /**
@@ -108,7 +108,7 @@ public Category getCategory() {
     }
 
     @POST
-    public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public synchronized void doConfigure(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         // for compatibility reasons, the actual value is stored in Jenkins
         JSONObject json = req.getSubmittedForm();
         BulkChange bc = new BulkChange(Jenkins.get());
@@ -125,7 +125,7 @@ public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) th
         }
     }
 
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         // for compatibility reasons, the actual value is stored in Jenkins
         Jenkins j = Jenkins.get();
         j.checkPermission(Jenkins.ADMINISTER);
@@ -171,7 +171,7 @@ public boolean configure(StaplerRequest req, JSONObject json) throws FormExcepti
         return result;
     }
 
-    private boolean configureDescriptor(StaplerRequest req, JSONObject json, Descriptor<?> d) throws FormException {
+    private boolean configureDescriptor(StaplerRequest2 req, JSONObject json, Descriptor<?> d) throws FormException {
         // collapse the structure to remain backward compatible with the JSON structure before 1.
         String name = d.getJsonSafeClassName();
         JSONObject js = json.has(name) ? json.getJSONObject(name) : new JSONObject(); // if it doesn't have the property, the method returns invalid null object.
diff --git a/core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java b/core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java
index 786df5d72879..c2c0d8a6abe1 100644
--- a/core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java
+++ b/core/src/main/java/hudson/security/HttpSessionContextIntegrationFilter2.java
@@ -25,13 +25,13 @@
 package hudson.security;
 
 import hudson.model.User;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpSession;
 import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
 import jenkins.security.seed.UserSeedProperty;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.core.Authentication;
diff --git a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java
index e99dfdc14f74..950cf3614c82 100644
--- a/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java
+++ b/core/src/main/java/hudson/security/HudsonAuthenticationEntryPoint.java
@@ -24,19 +24,19 @@
 
 package hudson.security;
 
-import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
+import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
 
 import hudson.Functions;
 import hudson.Util;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.text.MessageFormat;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.springframework.security.authentication.InsufficientAuthenticationException;
diff --git a/core/src/main/java/hudson/security/HudsonFilter.java b/core/src/main/java/hudson/security/HudsonFilter.java
index 333180b32ead..4438874b6030 100644
--- a/core/src/main/java/hudson/security/HudsonFilter.java
+++ b/core/src/main/java/hudson/security/HudsonFilter.java
@@ -26,17 +26,18 @@
 
 import static java.util.logging.Level.SEVERE;
 
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.userdetails.UserDetailsService;
 import org.springframework.security.web.authentication.RememberMeServices;
@@ -52,7 +53,7 @@
  * @author Kohsuke Kawaguchi
  * @since 1.160
  */
-public class HudsonFilter implements Filter {
+public class HudsonFilter implements CompatibleFilter {
     /**
      * The SecurityRealm specific filter.
      */
diff --git a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
index bd122244c7e2..1a6ebe66f749 100644
--- a/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
+++ b/core/src/main/java/hudson/security/HudsonPrivateSecurityRealm.java
@@ -24,7 +24,7 @@
 
 package hudson.security;
 
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
 
 import com.thoughtworks.xstream.converters.UnmarshallingContext;
 import edu.umd.cs.findbugs.annotations.NonNull;
@@ -47,6 +47,15 @@
 import hudson.util.Protector;
 import hudson.util.Scrambler;
 import hudson.util.XStream2;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 import java.io.IOException;
 import java.lang.reflect.Constructor;
 import java.nio.charset.StandardCharsets;
@@ -67,15 +76,6 @@
 import java.util.regex.Pattern;
 import javax.crypto.SecretKeyFactory;
 import javax.crypto.spec.PBEKeySpec;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 import jenkins.model.Jenkins;
 import jenkins.security.FIPS140;
 import jenkins.security.SecurityListener;
@@ -85,14 +85,15 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.ForwardToView;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.mindrot.jbcrypt.BCrypt;
 import org.springframework.security.authentication.BadCredentialsException;
@@ -236,10 +237,10 @@ protected UserDetails authenticate2(String username, String password) throws Aut
     @Override
     public HttpResponse commenceSignup(final FederatedIdentity identity) {
         // store the identity in the session so that we can use this later
-        Stapler.getCurrentRequest().getSession().setAttribute(FEDERATED_IDENTITY_SESSION_KEY, identity);
+        Stapler.getCurrentRequest2().getSession().setAttribute(FEDERATED_IDENTITY_SESSION_KEY, identity);
         return new ForwardToView(this, "signupWithFederatedIdentity.jelly") {
             @Override
-            public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                 SignupInfo si = new SignupInfo(identity);
                 si.errorMessage = Messages.HudsonPrivateSecurityRealm_WouldYouLikeToSignUp(identity.getPronoun(), identity.getIdentifier());
                 req.setAttribute("data", si);
@@ -253,7 +254,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod
      * with {@link #commenceSignup}.
      */
     @RequirePOST
-    public User doCreateAccountWithFederatedIdentity(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public User doCreateAccountWithFederatedIdentity(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         User u = _doCreateAccount(req, rsp, "signupWithFederatedIdentity.jelly");
         if (u != null)
             ((FederatedIdentity) req.getSession().getAttribute(FEDERATED_IDENTITY_SESSION_KEY)).addTo(u);
@@ -266,11 +267,11 @@ public User doCreateAccountWithFederatedIdentity(StaplerRequest req, StaplerResp
      * Creates an user account. Used for self-registration.
      */
     @RequirePOST
-    public User doCreateAccount(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public User doCreateAccount(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         return _doCreateAccount(req, rsp, "signup.jelly");
     }
 
-    private User _doCreateAccount(StaplerRequest req, StaplerResponse rsp, String formView) throws ServletException, IOException {
+    private User _doCreateAccount(StaplerRequest2 req, StaplerResponse2 rsp, String formView) throws ServletException, IOException {
         if (!allowsSignup())
             throw HttpResponses.errorWithoutStack(SC_UNAUTHORIZED, "User sign up is prohibited");
 
@@ -287,7 +288,7 @@ private User _doCreateAccount(StaplerRequest req, StaplerResponse rsp, String fo
     /**
      * Lets the current user silently login as the given user and report back accordingly.
      */
-    private void loginAndTakeBack(StaplerRequest req, StaplerResponse rsp, User u) throws ServletException, IOException {
+    private void loginAndTakeBack(StaplerRequest2 req, StaplerResponse2 rsp, User u) throws ServletException, IOException {
         HttpSession session = req.getSession(false);
         if (session != null) {
             // avoid session fixation
@@ -309,11 +310,11 @@ private void loginAndTakeBack(StaplerRequest req, StaplerResponse rsp, User u) t
     /**
      * Creates a user account. Used by admins.
      *
-     * This version behaves differently from {@link #doCreateAccount(StaplerRequest, StaplerResponse)} in that
+     * This version behaves differently from {@link #doCreateAccount(StaplerRequest2, StaplerResponse2)} in that
      * this is someone creating another user.
      */
     @RequirePOST
-    public void doCreateAccountByAdmin(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doCreateAccountByAdmin(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         createAccountByAdmin(req, rsp, "addUser.jelly", "."); // send the user back to the listing page on success
     }
 
@@ -321,7 +322,7 @@ public void doCreateAccountByAdmin(StaplerRequest req, StaplerResponse rsp) thro
      * Creates a user account. Requires {@link Jenkins#ADMINISTER}
      */
     @Restricted(NoExternalUse.class)
-    public User createAccountByAdmin(StaplerRequest req, StaplerResponse rsp, String addUserView, String successView) throws IOException, ServletException {
+    public User createAccountByAdmin(StaplerRequest2 req, StaplerResponse2 rsp, String addUserView, String successView) throws IOException, ServletException {
         checkPermission(Jenkins.ADMINISTER);
         User u = createAccount(req, rsp, false, addUserView);
         if (u != null && successView != null) {
@@ -340,7 +341,7 @@ public User createAccountByAdmin(StaplerRequest req, StaplerResponse rsp, String
      * @throws AccountCreationFailedException if account creation failed due to invalid form input
      */
     @Restricted(NoExternalUse.class)
-    public User createAccountFromSetupWizard(StaplerRequest req) throws IOException, AccountCreationFailedException {
+    public User createAccountFromSetupWizard(StaplerRequest2 req) throws IOException, AccountCreationFailedException {
         checkPermission(Jenkins.ADMINISTER);
         SignupInfo si = validateAccountCreationForm(req, false);
         if (!si.errors.isEmpty()) {
@@ -366,7 +367,7 @@ private String getErrorMessages(SignupInfo si) {
      * This can be run by anyone, but only to create the very first user account.
      */
     @RequirePOST
-    public void doCreateFirstAccount(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doCreateFirstAccount(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         if (hasSomeUser()) {
             rsp.sendError(SC_UNAUTHORIZED, "First user was already created");
             return;
@@ -400,7 +401,7 @@ private void tryToMakeAdmin(User u) {
      *      null if failed. The browser is already redirected to retry by the time this method returns.
      *      a valid {@link User} object if the user creation was successful.
      */
-    private User createAccount(StaplerRequest req, StaplerResponse rsp, boolean validateCaptcha, String formView) throws ServletException, IOException {
+    private User createAccount(StaplerRequest2 req, StaplerResponse2 rsp, boolean validateCaptcha, String formView) throws ServletException, IOException {
         SignupInfo si = validateAccountCreationForm(req, validateCaptcha);
 
         if (!si.errors.isEmpty()) {
@@ -416,11 +417,11 @@ private User createAccount(StaplerRequest req, StaplerResponse rsp, boolean vali
      * @param req              the request to process
      * @param validateCaptcha  whether to attempt to validate a captcha in the request
      *
-     * @return a {@link SignupInfo#SignupInfo(StaplerRequest) SignupInfo from given request}, with {@link
+     * @return a {@link SignupInfo#SignupInfo(StaplerRequest2) SignupInfo from given request}, with {@link
      * SignupInfo#errors} containing errors (keyed by field name), if any of the supported fields are invalid
      */
     @SuppressFBWarnings(value = "UWF_UNWRITTEN_PUBLIC_OR_PROTECTED_FIELD", justification = "written to by Stapler")
-    private SignupInfo validateAccountCreationForm(StaplerRequest req, boolean validateCaptcha) {
+    private SignupInfo validateAccountCreationForm(StaplerRequest2 req, boolean validateCaptcha) {
         // form field validation
         // this pattern needs to be generalized and moved to stapler
         SignupInfo si = new SignupInfo(req);
@@ -632,7 +633,7 @@ public static final class SignupInfo {
         public SignupInfo() {
         }
 
-        public SignupInfo(StaplerRequest req) {
+        public SignupInfo(StaplerRequest2 req) {
             req.bindParameters(this);
         }
 
@@ -707,7 +708,7 @@ public boolean isPasswordCorrect(String candidate) {
 
         public String getProtectedPassword() {
             // put session Id in it to prevent a replay attack.
-            return Protector.protect(Stapler.getCurrentRequest().getSession().getId() + ':' + getPassword());
+            return Protector.protect(Stapler.getCurrentRequest2().getSession().getId() + ':' + getPassword());
         }
 
         public String getUsername() {
@@ -825,7 +826,7 @@ public String getDisplayName() {
             }
 
             @Override
-            public Details newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            public Details newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
                 if (req == null) {
                     // Should never happen, see newInstance() Javadoc
                     throw new FormException("Stapler request is missing in the call", "staplerRequest");
@@ -858,7 +859,7 @@ public Details newInstance(StaplerRequest req, JSONObject formData) throws FormE
                 }
 
                 if (data != null) {
-                    String prefix = Stapler.getCurrentRequest().getSession().getId() + ':';
+                    String prefix = Stapler.getCurrentRequest2().getSession().getId() + ':';
                     if (data.startsWith(prefix)) {
                         return Details.fromHashedPassword(data.substring(prefix.length()));
                     }
@@ -1153,7 +1154,7 @@ public FormValidation doCheckAllowsSignup(@QueryParameter boolean value) {
         }
     }
 
-    private static final Filter CREATE_FIRST_USER_FILTER = new Filter() {
+    private static final Filter CREATE_FIRST_USER_FILTER = new CompatibleFilter() {
         @Override
         public void init(FilterConfig config) throws ServletException {
         }
diff --git a/core/src/main/java/hudson/security/LegacySecurityRealm.java b/core/src/main/java/hudson/security/LegacySecurityRealm.java
index 1e869475caf2..94c895782f74 100644
--- a/core/src/main/java/hudson/security/LegacySecurityRealm.java
+++ b/core/src/main/java/hudson/security/LegacySecurityRealm.java
@@ -28,10 +28,10 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.Extension;
 import hudson.model.Descriptor;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterConfig;
 import java.util.ArrayList;
 import java.util.List;
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
diff --git a/core/src/main/java/hudson/security/NoopFilter.java b/core/src/main/java/hudson/security/NoopFilter.java
index 3000bb2e81c0..2b2db184fc5f 100644
--- a/core/src/main/java/hudson/security/NoopFilter.java
+++ b/core/src/main/java/hudson/security/NoopFilter.java
@@ -24,20 +24,21 @@
 
 package hudson.security;
 
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * {@link Filter} that does nothing.
  *
  * @author Kohsuke Kawaguchi
  */
-public class NoopFilter implements Filter {
+public class NoopFilter implements CompatibleFilter {
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
     }
diff --git a/core/src/main/java/hudson/security/RememberMeServicesProxy.java b/core/src/main/java/hudson/security/RememberMeServicesProxy.java
index 2220e313b0cc..1020002794ed 100644
--- a/core/src/main/java/hudson/security/RememberMeServicesProxy.java
+++ b/core/src/main/java/hudson/security/RememberMeServicesProxy.java
@@ -24,8 +24,8 @@
 
 package hudson.security;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.security.ConfidentialStore;
 import org.kohsuke.accmod.Restricted;
diff --git a/core/src/main/java/hudson/security/SecurityRealm.java b/core/src/main/java/hudson/security/SecurityRealm.java
index b969a57eb781..d10e7994ae22 100644
--- a/core/src/main/java/hudson/security/SecurityRealm.java
+++ b/core/src/main/java/hudson/security/SecurityRealm.java
@@ -36,6 +36,14 @@
 import hudson.security.captcha.CaptchaSupport;
 import hudson.util.DescriptorList;
 import hudson.util.PluginServletFilter;
+import io.jenkins.servlet.FilterConfigWrapper;
+import io.jenkins.servlet.FilterWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpSession;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -44,16 +52,12 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpSession;
 import jenkins.model.IdStrategy;
 import jenkins.model.Jenkins;
 import jenkins.security.AcegiSecurityExceptionFilter;
 import jenkins.security.AuthenticationSuccessHandler;
 import jenkins.security.BasicHeaderProcessor;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
@@ -62,7 +66,9 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.AuthenticationException;
@@ -264,7 +270,7 @@ public boolean canLogOut() {
      * of Hudson, but you can return arbitrary URL.
      *
      * @param req
-     *      {@link StaplerRequest} that represents the current request. Primarily so that
+     *      {@link StaplerRequest2} that represents the current request. Primarily so that
      *      you can get the context path. By the time this method is called, the session
      *      is already invalidated. Never null.
      * @param auth
@@ -272,14 +278,31 @@ public boolean canLogOut() {
      *      This parameter allows you to redirect people to different pages depending on who they are.
      * @return
      *      never null.
+     * @since TODO
+     * @see #doLogout(StaplerRequest2, StaplerResponse2)
+     */
+    protected String getPostLogOutUrl2(StaplerRequest2 req, Authentication auth) {
+        if (Util.isOverridden(SecurityRealm.class, getClass(), "getPostLogOutUrl2", StaplerRequest.class, Authentication.class)) {
+            return getPostLogOutUrl2(StaplerRequest.fromStaplerRequest2(req), auth);
+        } else {
+            return getPostLogOutUrl2Impl(req, auth);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #getPostLogOutUrl2(StaplerRequest2, Authentication)}
      * @since 2.266
-     * @see #doLogout(StaplerRequest, StaplerResponse)
      */
+    @Deprecated
     protected String getPostLogOutUrl2(StaplerRequest req, Authentication auth) {
+        return getPostLogOutUrl2Impl(StaplerRequest.toStaplerRequest2(req), auth);
+    }
+
+    private String getPostLogOutUrl2Impl(StaplerRequest2 req, Authentication auth) {
         if (Util.isOverridden(SecurityRealm.class, getClass(), "getPostLogOutUrl", StaplerRequest.class, org.acegisecurity.Authentication.class) && !insideGetPostLogOutUrl.get()) {
             insideGetPostLogOutUrl.set(true);
             try {
-                return getPostLogOutUrl(req, org.acegisecurity.Authentication.fromSpring(auth));
+                return getPostLogOutUrl(StaplerRequest.fromStaplerRequest2(req), org.acegisecurity.Authentication.fromSpring(auth));
             } finally {
                 insideGetPostLogOutUrl.set(false);
             }
@@ -295,7 +318,7 @@ protected String getPostLogOutUrl2(StaplerRequest req, Authentication auth) {
      */
     @Deprecated
     protected String getPostLogOutUrl(StaplerRequest req, org.acegisecurity.Authentication auth) {
-        return getPostLogOutUrl2(req, auth.toSpring());
+        return getPostLogOutUrl2(StaplerRequest.toStaplerRequest2(req), auth.toSpring());
     }
 
     public CaptchaSupport getCaptchaSupport() {
@@ -315,11 +338,37 @@ public List<Descriptor<CaptchaSupport>> getCaptchaSupportDescriptors() {
      *
      * <p>
      * The default implementation erases the session and do a few other clean up, then
-     * redirect the user to the URL specified by {@link #getPostLogOutUrl2(StaplerRequest, Authentication)}.
+     * redirect the user to the URL specified by {@link #getPostLogOutUrl2(StaplerRequest2, Authentication)}.
      *
+     * @since TODO
+     */
+    public void doLogout(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(SecurityRealm.class, getClass(), "doLogout", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                doLogout(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            doLogoutImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doLogout(StaplerRequest2, StaplerResponse2)}
      * @since 1.314
      */
-    public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doLogoutImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    void doLogoutImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         HttpSession session = req.getSession(false);
         if (session != null)
             session.invalidate();
@@ -333,7 +382,7 @@ public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException
         rsp.sendRedirect2(getPostLogOutUrl2(req, auth));
     }
 
-    private void resetRememberMeCookie(StaplerRequest req, StaplerResponse rsp, String contextPath) {
+    private void resetRememberMeCookie(StaplerRequest2 req, StaplerResponse2 rsp, String contextPath) {
         Cookie cookie = new Cookie(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY, "");
         cookie.setMaxAge(0);
         cookie.setSecure(req.isSecure());
@@ -342,7 +391,7 @@ private void resetRememberMeCookie(StaplerRequest req, StaplerResponse rsp, Stri
         rsp.addCookie(cookie);
     }
 
-    private void clearStaleSessionCookies(StaplerRequest req, StaplerResponse rsp, String contextPath) {
+    private void clearStaleSessionCookies(StaplerRequest2 req, StaplerResponse2 rsp, String contextPath) {
         /* While "executableWar.jetty.sessionIdCookieName" and
          * "executableWar.jetty.disableCustomSessionIdCookieName"
          * <https://github.com/jenkinsci/extras-executable-war/blob/6558df699d1366b18d045d2ffda3e970df377873/src/main/java/Main.java#L79-L97>
@@ -516,7 +565,7 @@ public HttpResponse commenceSignup(FederatedIdentity identity) {
     /**
      * Generates a captcha image.
      */
-    public final void doCaptcha(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public final void doCaptcha(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (captchaSupport != null) {
             String id = req.getSession().getId();
             rsp.setContentType("image/png");
@@ -533,7 +582,7 @@ public final void doCaptcha(StaplerRequest req, StaplerResponse rsp) throws IOEx
      */
     protected final boolean validateCaptcha(String text) {
         if (captchaSupport != null) {
-            String id = Stapler.getCurrentRequest().getSession().getId();
+            String id = Stapler.getCurrentRequest2().getSession().getId();
             return captchaSupport.validateCaptcha(id, text);
         }
 
@@ -570,10 +619,29 @@ public synchronized SecurityComponents getSecurityComponents() {
      * For other plugins that want to contribute {@link Filter}, see
      * {@link PluginServletFilter}.
      *
-     * @since 1.271
+     * @since TODO
      */
     public Filter createFilter(FilterConfig filterConfig) {
-        LOGGER.entering(SecurityRealm.class.getName(), "createFilter");
+        if (Util.isOverridden(SecurityRealm.class, getClass(), "createFilter", javax.servlet.FilterConfig.class)) {
+            return FilterWrapper.toJakartaFilter(createFilter(
+                    filterConfig != null ? FilterConfigWrapper.fromJakartaFilterConfig(filterConfig) : null));
+        } else {
+            return createFilterImpl(filterConfig);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #createFilter(FilterConfig)}
+     * @since 1.271
+     */
+    @Deprecated
+    public javax.servlet.Filter createFilter(javax.servlet.FilterConfig filterConfig) {
+        return FilterWrapper.fromJakartaFilter(createFilterImpl(
+                filterConfig != null ? FilterConfigWrapper.toJakartaFilterConfig(filterConfig) : null));
+    }
+
+    private Filter createFilterImpl(FilterConfig filterConfig) {
+        LOGGER.entering(SecurityRealm.class.getName(), "createFilterImpl");
 
         SecurityComponents sc = getSecurityComponents();
         List<Filter> filters = new ArrayList<>();
@@ -639,7 +707,7 @@ protected final List<Filter> commonFilters() {
     @Restricted(DoNotUse.class)
     public static String getFrom() {
         String from = null;
-        final StaplerRequest request = Stapler.getCurrentRequest();
+        final StaplerRequest2 request = Stapler.getCurrentRequest2();
 
         // Try to obtain a return point from the query parameter
         if (request != null) {
@@ -734,7 +802,7 @@ public String getDisplayName() {
             }
 
             @Override
-            public SecurityRealm newInstance(StaplerRequest req, JSONObject formData) throws Descriptor.FormException {
+            public SecurityRealm newInstance(StaplerRequest2 req, JSONObject formData) throws Descriptor.FormException {
                 return NO_AUTHENTICATION;
             }
         }
diff --git a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java
index 0e8e19d90a06..9b6974a3f2e4 100644
--- a/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java
+++ b/core/src/main/java/hudson/security/TokenBasedRememberMeServices2.java
@@ -27,6 +27,8 @@
 import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.model.User;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.security.MessageDigest;
 import java.util.Arrays;
 import java.util.Date;
@@ -34,8 +36,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.security.HMACConfidentialKey;
 import jenkins.security.ImpersonatingUserDetailsService2;
diff --git a/core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java b/core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java
index 2abfea11eb71..683725b2fe0d 100644
--- a/core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java
+++ b/core/src/main/java/hudson/security/UnwrapSecurityExceptionFilter.java
@@ -24,14 +24,14 @@
 
 package hudson.security;
 
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import org.apache.commons.jelly.JellyTagException;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.AuthenticationException;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
@@ -43,7 +43,7 @@
  *
  * @author Kohsuke Kawaguchi
  */
-public class UnwrapSecurityExceptionFilter implements Filter {
+public class UnwrapSecurityExceptionFilter implements CompatibleFilter {
     @Override
     public void init(FilterConfig filterConfig) throws ServletException {
     }
diff --git a/core/src/main/java/hudson/security/csrf/CrumbExclusion.java b/core/src/main/java/hudson/security/csrf/CrumbExclusion.java
index 4f4135bd9a88..e7d8d67a219f 100644
--- a/core/src/main/java/hudson/security/csrf/CrumbExclusion.java
+++ b/core/src/main/java/hudson/security/csrf/CrumbExclusion.java
@@ -8,11 +8,16 @@
 
 import hudson.ExtensionList;
 import hudson.ExtensionPoint;
+import hudson.Util;
+import io.jenkins.servlet.FilterChainWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import io.jenkins.servlet.http.HttpServletRequestWrapper;
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 /**
  * Allows plugins to define exceptions to the CSRF protection filter.
@@ -32,7 +37,57 @@ public abstract class CrumbExclusion implements ExtensionPoint {
      *      true to indicate that the callee had processed this request
      *      (for example by reporting an error, or by executing the rest of the chain.)
      */
-    public abstract boolean process(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException;
+    public /* abstract */ boolean process(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+        if (Util.isOverridden(
+                CrumbExclusion.class,
+                getClass(),
+                "process",
+                javax.servlet.http.HttpServletRequest.class,
+                javax.servlet.http.HttpServletResponse.class,
+                javax.servlet.FilterChain.class)) {
+            try {
+                return process(
+                        HttpServletRequestWrapper.fromJakartaHttpServletRequest(request),
+                        HttpServletResponseWrapper.fromJakartaHttpServletResponse(response),
+                        FilterChainWrapper.fromJakartaFilterChain(chain));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + CrumbExclusion.class.getSimpleName() + ".process methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #process(HttpServletRequest, HttpServletResponse, FilterChain)}
+     */
+    @Deprecated
+    public boolean process(
+            javax.servlet.http.HttpServletRequest request,
+            javax.servlet.http.HttpServletResponse response,
+            javax.servlet.FilterChain chain)
+            throws IOException, javax.servlet.ServletException {
+        if (Util.isOverridden(
+                CrumbExclusion.class,
+                getClass(),
+                "process",
+                HttpServletRequest.class,
+                HttpServletResponse.class,
+                FilterChain.class)) {
+            try {
+                return process(
+                        HttpServletRequestWrapper.toJakartaHttpServletRequest(request),
+                        HttpServletResponseWrapper.toJakartaHttpServletResponse(response),
+                        FilterChainWrapper.toJakartaFilterChain(chain));
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + CrumbExclusion.class.getSimpleName() + ".process methods");
+        }
+    }
 
     public static ExtensionList<CrumbExclusion> all() {
         return ExtensionList.lookup(CrumbExclusion.class);
diff --git a/core/src/main/java/hudson/security/csrf/CrumbFilter.java b/core/src/main/java/hudson/security/csrf/CrumbFilter.java
index 8b4b558938e7..6835a4365a3c 100644
--- a/core/src/main/java/hudson/security/csrf/CrumbFilter.java
+++ b/core/src/main/java/hudson/security/csrf/CrumbFilter.java
@@ -7,6 +7,14 @@
 package hudson.security.csrf;
 
 import hudson.util.MultipartFormDataParser;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -14,20 +22,12 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import org.kohsuke.MetaInfServices;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.kohsuke.stapler.ForwardToView;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
@@ -38,7 +38,7 @@
  *
  * @author dty
  */
-public class CrumbFilter implements Filter {
+public class CrumbFilter implements CompatibleFilter {
     /**
      * Because servlet containers generally don't specify the ordering of the initialization
      * (and different implementations indeed do this differently --- See JENKINS-3878),
diff --git a/core/src/main/java/hudson/security/csrf/CrumbIssuer.java b/core/src/main/java/hudson/security/csrf/CrumbIssuer.java
index cd0c51b03fb0..491ec735b591 100644
--- a/core/src/main/java/hudson/security/csrf/CrumbIssuer.java
+++ b/core/src/main/java/hudson/security/csrf/CrumbIssuer.java
@@ -6,26 +6,31 @@
 
 package hudson.security.csrf;
 
+import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.DescriptorExtensionList;
 import hudson.ExtensionPoint;
+import hudson.Util;
 import hudson.init.Initializer;
 import hudson.model.Api;
 import hudson.model.Describable;
 import hudson.model.Descriptor;
 import hudson.util.MultipartFormDataParser;
+import io.jenkins.servlet.ServletRequestWrapper;
+import io.jenkins.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
 import jenkins.model.Jenkins;
 import jenkins.security.stapler.StaplerAccessibleType;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -64,7 +69,7 @@ public String getCrumbRequestField() {
      */
     @Exported
     public String getCrumb() {
-        return getCrumb(Stapler.getCurrentRequest());
+        return getCrumb(Stapler.getCurrentRequest2());
     }
 
     /**
@@ -89,6 +94,14 @@ public String getCrumb(ServletRequest request) {
         return crumb;
     }
 
+    /**
+     * @deprecated use {@link #getCrumb(ServletRequest)}
+     */
+    @Deprecated
+    public String getCrumb(javax.servlet.ServletRequest request) {
+        return getCrumb(request != null ? wrap(request) : null);
+    }
+
     /**
      * Create a crumb value based on user specific information in the request.
      * The crumb should be generated by building a cryptographic hash of:
@@ -98,7 +111,30 @@ public String getCrumb(ServletRequest request) {
      *  <li>an implementation specific guarded secret.
      * </ul>
      */
-    protected abstract String issueCrumb(ServletRequest request, String salt);
+    protected /* abstract */ String issueCrumb(ServletRequest request, String salt) {
+        return Util.ifOverridden(
+                () -> issueCrumb(
+                        request != null ? wrap(request) : null, salt),
+                CrumbIssuer.class,
+                getClass(),
+                "issueCrumb",
+                javax.servlet.ServletRequest.class,
+                String.class);
+    }
+
+    /**
+     * @deprecated use {@link #issueCrumb(ServletRequest, String)}
+     */
+    @Deprecated
+    protected String issueCrumb(javax.servlet.ServletRequest request, String salt) {
+        return Util.ifOverridden(
+                () -> issueCrumb(request != null ? wrap(request) : null, salt),
+                CrumbIssuer.class,
+                getClass(),
+                "issueCrumb",
+                ServletRequest.class,
+                String.class);
+    }
 
     /**
      * Get a crumb from a request parameter and validate it against other data
@@ -126,12 +162,63 @@ public boolean validateCrumb(ServletRequest request, MultipartFormDataParser par
         return validateCrumb(request, crumbSalt, parser.get(crumbField));
     }
 
+    /**
+     * @deprecated use {@link #validateCrumb(ServletRequest, MultipartFormDataParser)}
+     */
+    @Deprecated
+    public boolean validateCrumb(javax.servlet.ServletRequest request, MultipartFormDataParser parser) {
+        return validateCrumb(request != null ? wrap(request) : null, parser);
+    }
+
+    private static ServletRequest wrap(@NonNull javax.servlet.ServletRequest request) {
+        if (request instanceof javax.servlet.http.HttpServletRequest httpRequest) {
+            return HttpServletRequestWrapper.toJakartaHttpServletRequest(httpRequest);
+        } else {
+            return ServletRequestWrapper.toJakartaServletRequest(request);
+        }
+    }
+
     /**
      * Validate a previously created crumb against information in the current request.
      *
      * @param crumb The previously generated crumb to validate against information in the current request
      */
-    public abstract boolean validateCrumb(ServletRequest request, String salt, String crumb);
+    public /* abstract */ boolean validateCrumb(ServletRequest request, String salt, String crumb) {
+        return Util.ifOverridden(
+                () -> validateCrumb(
+                        request != null ? wrap(request) : null,
+                        salt,
+                        crumb),
+                CrumbIssuer.class,
+                getClass(),
+                "validateCrumb",
+                javax.servlet.ServletRequest.class,
+                String.class,
+                String.class);
+    }
+
+    private static javax.servlet.ServletRequest wrap(@NonNull ServletRequest request) {
+        if (request instanceof HttpServletRequest httpRequest) {
+            return HttpServletRequestWrapper.fromJakartaHttpServletRequest(httpRequest);
+        } else {
+            return ServletRequestWrapper.fromJakartaServletRequest(request);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #validateCrumb(ServletRequest, String, String)}
+     */
+    @Deprecated
+    public boolean validateCrumb(javax.servlet.ServletRequest request, String salt, String crumb) {
+        return Util.ifOverridden(
+                () -> validateCrumb(request != null ? wrap(request) : null, salt, crumb),
+                CrumbIssuer.class,
+                getClass(),
+                "validateCrumb",
+                ServletRequest.class,
+                String.class,
+                String.class);
+    }
 
     /**
      * Access global configuration for the crumb issuer.
@@ -157,15 +244,15 @@ public Api getApi() {
      */
     @Initializer
     public static void initStaplerCrumbIssuer() {
-        WebApp.get(Jenkins.get().servletContext).setCrumbIssuer(new org.kohsuke.stapler.CrumbIssuer() {
+        WebApp.get(Jenkins.get().getServletContext()).setCrumbIssuer(new org.kohsuke.stapler.CrumbIssuer() {
             @Override
-            public String issueCrumb(StaplerRequest request) {
+            public String issueCrumb(StaplerRequest2 request) {
                 CrumbIssuer ci = Jenkins.get().getCrumbIssuer();
                 return ci != null ? ci.getCrumb(request) : DEFAULT.issueCrumb(request);
             }
 
             @Override
-            public void validateCrumb(StaplerRequest request, String submittedCrumb) {
+            public void validateCrumb(StaplerRequest2 request, String submittedCrumb) {
                 CrumbIssuer ci = Jenkins.get().getCrumbIssuer();
                 if (ci == null) {
                     DEFAULT.validateCrumb(request, submittedCrumb);
@@ -184,7 +271,7 @@ public static class RestrictedApi extends Api {
             super(instance);
         }
 
-        @Override public void doXml(StaplerRequest req, StaplerResponse rsp, @QueryParameter String xpath, @QueryParameter String wrapper, @QueryParameter String tree, @QueryParameter int depth) throws IOException, ServletException {
+        @Override public void doXml(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String xpath, @QueryParameter String wrapper, @QueryParameter String tree, @QueryParameter int depth) throws IOException, ServletException {
             setHeaders(rsp);
             String text;
             CrumbIssuer ci = (CrumbIssuer) bean;
diff --git a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java
index 89c7da39e7b4..7a3bc0c9b1d2 100644
--- a/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java
+++ b/core/src/main/java/hudson/security/csrf/DefaultCrumbIssuer.java
@@ -12,13 +12,13 @@
 import hudson.Util;
 import hudson.model.ModelObject;
 import hudson.model.PersistentDescriptor;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
 import java.nio.charset.StandardCharsets;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletRequest;
-import javax.servlet.http.HttpServletRequest;
 import jenkins.model.Jenkins;
 import jenkins.security.HexStringConfidentialKey;
 import jenkins.util.SystemProperties;
@@ -27,7 +27,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.core.Authentication;
 
 /**
@@ -69,6 +69,7 @@ private synchronized void initializeMessageDigest() {
     }
 
     @Override
+    @SuppressFBWarnings(value = "NM_WRONG_PACKAGE", justification = "false positive")
     protected synchronized String issueCrumb(ServletRequest request, String salt) {
         if (request instanceof HttpServletRequest) {
             if (md != null) {
@@ -135,7 +136,7 @@ public String getDisplayName() {
         }
 
         @Override
-        public DefaultCrumbIssuer newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public DefaultCrumbIssuer newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             if (req == null) {
                 // This state is prohibited according to the Javadoc of the super method.
                 throw new FormException("DefaultCrumbIssuer new instance method is called for null Stapler request. "
diff --git a/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java b/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java
index 6faa5dfc24e0..61a861fefbe3 100644
--- a/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java
+++ b/core/src/main/java/hudson/security/csrf/GlobalCrumbIssuerConfiguration.java
@@ -35,7 +35,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Show the crumb configuration to the system config page.
@@ -50,7 +50,7 @@ public class GlobalCrumbIssuerConfiguration extends GlobalConfiguration {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         // for compatibility reasons, the actual value is stored in Jenkins
         Jenkins j = Jenkins.get();
 
diff --git a/core/src/main/java/hudson/slaves/Cloud.java b/core/src/main/java/hudson/slaves/Cloud.java
index 6552685a05d0..3bff60c0d0ad 100644
--- a/core/src/main/java/hudson/slaves/Cloud.java
+++ b/core/src/main/java/hudson/slaves/Cloud.java
@@ -47,11 +47,11 @@
 import hudson.slaves.NodeProvisioner.PlannedNode;
 import hudson.util.DescriptorList;
 import hudson.util.FormApply;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.Collection;
 import java.util.Objects;
 import java.util.concurrent.Future;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
@@ -60,7 +60,8 @@
 import org.kohsuke.stapler.HttpRedirect;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
 
@@ -319,7 +320,7 @@ public HttpResponse doDoDelete() throws IOException {
      * Accepts the update to the node configuration.
      */
     @POST
-    public HttpResponse doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    public HttpResponse doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         checkPermission(Jenkins.ADMINISTER);
 
         Jenkins j = Jenkins.get();
@@ -340,7 +341,26 @@ public HttpResponse doConfigSubmit(StaplerRequest req, StaplerResponse rsp) thro
 
     }
 
+    /**
+     * @since TODO
+     */
+    public Cloud reconfigure(@NonNull final StaplerRequest2 req, JSONObject form) throws Descriptor.FormException {
+        if (Util.isOverridden(Cloud.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #reconfigure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
     public Cloud reconfigure(@NonNull final StaplerRequest req, JSONObject form) throws Descriptor.FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private Cloud reconfigureImpl(@NonNull final StaplerRequest2 req, JSONObject form) throws Descriptor.FormException {
         if (form == null)     return null;
         return getDescriptor().newInstance(req, form);
     }
diff --git a/core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java b/core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java
index be50bc982062..dd3ec84b131d 100644
--- a/core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java
+++ b/core/src/main/java/hudson/slaves/EnvironmentVariablesNodeProperty.java
@@ -98,7 +98,7 @@ public String getDisplayName() {
 
         public String getHelpPage() {
             // yes, I know this is a hack.
-            ComputerSet object = Stapler.getCurrentRequest().findAncestorObject(ComputerSet.class);
+            ComputerSet object = Stapler.getCurrentRequest2().findAncestorObject(ComputerSet.class);
             if (object != null) {
                 // we're on a node configuration page, show show that help page
                 return "/help/system-config/nodeEnvironmentVariables.html";
diff --git a/core/src/main/java/hudson/slaves/NodeDescriptor.java b/core/src/main/java/hudson/slaves/NodeDescriptor.java
index 8db1eb48139f..848cabbdf747 100644
--- a/core/src/main/java/hudson/slaves/NodeDescriptor.java
+++ b/core/src/main/java/hudson/slaves/NodeDescriptor.java
@@ -34,14 +34,14 @@
 import hudson.model.Slave;
 import hudson.util.DescriptorList;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link Descriptor} for {@link Slave}.
@@ -83,7 +83,7 @@ public final String newInstanceDetailPage() {
      * @param name
      *      Name of the new node.
      */
-    public void handleNewNodePage(ComputerSet computerSet, String name, StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void handleNewNodePage(ComputerSet computerSet, String name, StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         computerSet.checkName(name);
         req.setAttribute("descriptor", this);
         req.getView(computerSet, "_new.jelly").forward(req, rsp);
diff --git a/core/src/main/java/hudson/slaves/NodeProperty.java b/core/src/main/java/hudson/slaves/NodeProperty.java
index 8605edcf4515..bcb2a2422025 100644
--- a/core/src/main/java/hudson/slaves/NodeProperty.java
+++ b/core/src/main/java/hudson/slaves/NodeProperty.java
@@ -30,6 +30,7 @@
 import hudson.ExtensionPoint;
 import hudson.FilePath;
 import hudson.Launcher;
+import hudson.Util;
 import hudson.model.AbstractBuild;
 import hudson.model.BuildListener;
 import hudson.model.Descriptor.FormException;
@@ -48,6 +49,7 @@
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Extensible property of {@link Node}.
@@ -171,8 +173,25 @@ public void buildEnvVars(@NonNull EnvVars env, @NonNull TaskListener listener) t
         // default is no-op
     }
 
+    @Override
+    public NodeProperty<?> reconfigure(StaplerRequest2 req, JSONObject form) throws FormException {
+        if (Util.isOverridden(NodeProperty.class, getClass(), "reconfigure", StaplerRequest.class, JSONObject.class)) {
+            return reconfigure(StaplerRequest.fromStaplerRequest2(req), form);
+        } else {
+            return reconfigureImpl(req, form);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #reconfigure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
     @Override
     public NodeProperty<?> reconfigure(StaplerRequest req, JSONObject form) throws FormException {
+        return reconfigureImpl(StaplerRequest.toStaplerRequest2(req), form);
+    }
+
+    private NodeProperty<?> reconfigureImpl(StaplerRequest2 req, JSONObject form) throws FormException {
         return form == null ? null : getDescriptor().newInstance(req, form);
     }
 
diff --git a/core/src/main/java/hudson/slaves/SlaveComputer.java b/core/src/main/java/hudson/slaves/SlaveComputer.java
index dbb579b9b3ae..4165f53a7245 100644
--- a/core/src/main/java/hudson/slaves/SlaveComputer.java
+++ b/core/src/main/java/hudson/slaves/SlaveComputer.java
@@ -97,8 +97,8 @@
 import org.kohsuke.stapler.HttpRedirect;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -788,7 +788,7 @@ public List<LogRecord> getLogRecords() throws IOException, InterruptedException
      */
     @RequirePOST
     @Restricted(NoExternalUse.class)
-    public synchronized void doSubmitDescription(StaplerResponse rsp, @QueryParameter String description) throws IOException {
+    public synchronized void doSubmitDescription(StaplerResponse2 rsp, @QueryParameter String description) throws IOException {
         checkPermission(CONFIGURE);
 
         final Slave node = this.getNode();
@@ -828,7 +828,7 @@ public void run() {
 
     @RequirePOST
     @Override
-    public void doLaunchSlaveAgent(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doLaunchSlaveAgent(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         checkPermission(CONNECT);
 
         if (channel != null) {
@@ -871,12 +871,12 @@ public Slave.JnlpJar getJnlpJars(String fileName) {
     }
 
     @WebMethod(name = "slave-agent.jnlp") // backward compatibility
-    public HttpResponse doSlaveAgentJnlp(StaplerRequest req, StaplerResponse res) {
+    public HttpResponse doSlaveAgentJnlp(StaplerRequest2 req, StaplerResponse2 res) {
         return doJenkinsAgentJnlp(req, res);
     }
 
     @WebMethod(name = "jenkins-agent.jnlp")
-    public HttpResponse doJenkinsAgentJnlp(StaplerRequest req, StaplerResponse res) {
+    public HttpResponse doJenkinsAgentJnlp(StaplerRequest2 req, StaplerResponse2 res) {
         LOGGER.log(
                 Level.WARNING,
                 "Agent \"" + getName()
@@ -888,12 +888,12 @@ public HttpResponse doJenkinsAgentJnlp(StaplerRequest req, StaplerResponse res)
 
     class LowPermissionResponse {
         @WebMethod(name = "jenkins-agent.jnlp")
-        public HttpResponse doJenkinsAgentJnlp(StaplerRequest req, StaplerResponse res) {
+        public HttpResponse doJenkinsAgentJnlp(StaplerRequest2 req, StaplerResponse2 res) {
             return SlaveComputer.this.doJenkinsAgentJnlp(req, res);
         }
 
         @WebMethod(name = "slave-agent.jnlp") // backward compatibility
-        public HttpResponse doSlaveAgentJnlp(StaplerRequest req, StaplerResponse res) {
+        public HttpResponse doSlaveAgentJnlp(StaplerRequest2 req, StaplerResponse2 res) {
             return SlaveComputer.this.doJenkinsAgentJnlp(req, res);
         }
     }
diff --git a/core/src/main/java/hudson/tasks/ArtifactArchiver.java b/core/src/main/java/hudson/tasks/ArtifactArchiver.java
index 4300cd1538ab..0ee50010e6a2 100644
--- a/core/src/main/java/hudson/tasks/ArtifactArchiver.java
+++ b/core/src/main/java/hudson/tasks/ArtifactArchiver.java
@@ -63,7 +63,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Copies the artifacts into an archive directory.
@@ -367,7 +367,7 @@ public FormValidation doCheckArtifacts(@AncestorInPath AbstractProject project,
         }
 
         @Override
-        public ArtifactArchiver newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public ArtifactArchiver newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             return req.bindJSON(ArtifactArchiver.class, formData);
         }
 
diff --git a/core/src/main/java/hudson/tasks/BuildTrigger.java b/core/src/main/java/hudson/tasks/BuildTrigger.java
index 5a58fc7e6716..af71ff83b147 100644
--- a/core/src/main/java/hudson/tasks/BuildTrigger.java
+++ b/core/src/main/java/hudson/tasks/BuildTrigger.java
@@ -73,7 +73,7 @@
 import org.kohsuke.stapler.AncestorInPath;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.core.Authentication;
 
 /**
@@ -385,7 +385,7 @@ public String getHelpFile() {
         }
 
         @Override
-        public BuildTrigger newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public BuildTrigger newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             String childProjectsString = formData.getString("childProjects").trim();
             if (childProjectsString.endsWith(",")) {
                 childProjectsString = childProjectsString.substring(0, childProjectsString.length() - 1).trim();
diff --git a/core/src/main/java/hudson/tasks/Fingerprinter.java b/core/src/main/java/hudson/tasks/Fingerprinter.java
index 4d843b27b003..2d41e338f212 100644
--- a/core/src/main/java/hudson/tasks/Fingerprinter.java
+++ b/core/src/main/java/hudson/tasks/Fingerprinter.java
@@ -76,7 +76,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.access.AccessDeniedException;
 
 /**
@@ -351,7 +351,7 @@ public FormValidation doCheckTargets(@AncestorInPath AbstractProject<?, ?> proje
         }
 
         @Override
-        public Publisher newInstance(StaplerRequest req, JSONObject formData) {
+        public Publisher newInstance(StaplerRequest2 req, JSONObject formData) {
             return req.bindJSON(Fingerprinter.class, formData);
         }
 
diff --git a/core/src/main/java/hudson/tasks/Maven.java b/core/src/main/java/hudson/tasks/Maven.java
index 3c22790d383c..2e9e27326b8e 100644
--- a/core/src/main/java/hudson/tasks/Maven.java
+++ b/core/src/main/java/hudson/tasks/Maven.java
@@ -80,7 +80,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Build by using Maven.
@@ -479,7 +479,7 @@ public void setInstallations(MavenInstallation... installations) {
         }
 
         @Override
-        public Builder newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+        public Builder newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
             if (req == null) {
                 // This state is prohibited according to the Javadoc of the super method.
                 throw new FormException("Maven Build Step new instance method is called for null Stapler request. "
diff --git a/core/src/main/java/hudson/tasks/Shell.java b/core/src/main/java/hudson/tasks/Shell.java
index e34c90b89d5c..9cd070136b55 100644
--- a/core/src/main/java/hudson/tasks/Shell.java
+++ b/core/src/main/java/hudson/tasks/Shell.java
@@ -53,7 +53,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Executes a series of commands by using a shell.
@@ -234,7 +234,7 @@ public FormValidation doCheckUnstableReturn(@QueryParameter String value) {
         }
 
         @Override
-        public boolean configure(StaplerRequest req, JSONObject data) throws FormException {
+        public boolean configure(StaplerRequest2 req, JSONObject data) throws FormException {
             req.bindJSON(this, data);
             return super.configure(req, data);
         }
diff --git a/core/src/main/java/hudson/tools/ToolDescriptor.java b/core/src/main/java/hudson/tools/ToolDescriptor.java
index cc9a2399196d..e20eb353af63 100644
--- a/core/src/main/java/hudson/tools/ToolDescriptor.java
+++ b/core/src/main/java/hudson/tools/ToolDescriptor.java
@@ -26,6 +26,7 @@
 
 import edu.umd.cs.findbugs.annotations.NonNull;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import hudson.Util;
 import hudson.model.Descriptor;
 import hudson.util.DescribableList;
 import hudson.util.FormValidation;
@@ -43,6 +44,7 @@
 import org.jvnet.tiger_types.Types;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link Descriptor} for {@link ToolInstallation}.
@@ -144,8 +146,25 @@ public DescribableList<ToolProperty<?>, ToolPropertyDescriptor> getDefaultProper
     }
 
     @Override
-    @SuppressWarnings("unchecked") // cast to T[]
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
+        if (Util.isOverridden(ToolDescriptor.class, getClass(), "configure", StaplerRequest.class, JSONObject.class)) {
+            return configure(StaplerRequest.fromStaplerRequest2(req), json);
+        } else {
+            return configureImpl(req, json);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #configure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
+    @Override
     public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+        return configureImpl(StaplerRequest.toStaplerRequest2(req), json);
+    }
+
+    @SuppressWarnings("unchecked") // cast to T[]
+    private boolean configureImpl(StaplerRequest2 req, JSONObject json) {
         setInstallations(req.bindJSONToList(clazz, json.get("tool")).toArray((T[]) Array.newInstance(clazz, 0)));
         return true;
     }
diff --git a/core/src/main/java/hudson/triggers/SCMTrigger.java b/core/src/main/java/hudson/triggers/SCMTrigger.java
index 43fdc6bb1062..f8277a345198 100644
--- a/core/src/main/java/hudson/triggers/SCMTrigger.java
+++ b/core/src/main/java/hudson/triggers/SCMTrigger.java
@@ -89,8 +89,8 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link Trigger} that checks for SCM updates periodically.
@@ -356,7 +356,7 @@ public boolean isPollingThreadCountOptionVisible() {
         }
 
         @Override
-        public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+        public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
             String t = json.optString("pollingThreadCount", null);
             if (doCheckPollingThreadCount(t).kind != FormValidation.Kind.OK) {
                 setPollingThreadCount(THREADS_DEFAULT);
@@ -466,7 +466,7 @@ public String getUrlName() {
         /**
          * Sends out the raw polling log output.
          */
-        public void doPollingLog(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doPollingLog(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             rsp.setContentType("text/plain;charset=UTF-8");
             try (OutputStream os = rsp.getOutputStream();
                  // Prevent jelly from flushing stream so Content-Length header can be added afterwards
diff --git a/core/src/main/java/hudson/util/BootFailure.java b/core/src/main/java/hudson/util/BootFailure.java
index f23cf7fa66b7..321d8239664c 100644
--- a/core/src/main/java/hudson/util/BootFailure.java
+++ b/core/src/main/java/hudson/util/BootFailure.java
@@ -2,6 +2,7 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.WebAppMain;
+import jakarta.servlet.ServletContext;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -14,7 +15,6 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
 import jenkins.model.Jenkins;
 import jenkins.util.groovy.GroovyHookScript;
 import org.kohsuke.stapler.WebApp;
diff --git a/core/src/main/java/hudson/util/CharacterEncodingFilter.java b/core/src/main/java/hudson/util/CharacterEncodingFilter.java
index cb93c31e7d4a..2e42c0d8098c 100644
--- a/core/src/main/java/hudson/util/CharacterEncodingFilter.java
+++ b/core/src/main/java/hudson/util/CharacterEncodingFilter.java
@@ -24,17 +24,17 @@
 
 package hudson.util;
 
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
 import jenkins.util.SystemProperties;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * Filter that sets the character encoding to be used in parsing the request
@@ -42,7 +42,7 @@
  *
  * @author Seiji Sogabe
  */
-public class CharacterEncodingFilter implements Filter {
+public class CharacterEncodingFilter implements CompatibleFilter {
 
     /**
      * The default character encoding.
diff --git a/core/src/main/java/hudson/util/ComboBoxModel.java b/core/src/main/java/hudson/util/ComboBoxModel.java
index e245c890db2e..63cac72f4d0d 100644
--- a/core/src/main/java/hudson/util/ComboBoxModel.java
+++ b/core/src/main/java/hudson/util/ComboBoxModel.java
@@ -26,15 +26,15 @@
 
 import static java.util.Arrays.asList;
 
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collection;
-import javax.servlet.ServletException;
 import net.sf.json.JSONArray;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Flavor;
 
 /**
@@ -59,7 +59,7 @@ public ComboBoxModel(String... values) {
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         rsp.setContentType(Flavor.JSON.contentType);
         PrintWriter w = rsp.getWriter();
         JSONArray.fromObject(this).write(w);
diff --git a/core/src/main/java/hudson/util/DescribableList.java b/core/src/main/java/hudson/util/DescribableList.java
index 9c62af2f191a..dbb499b4df66 100644
--- a/core/src/main/java/hudson/util/DescribableList.java
+++ b/core/src/main/java/hudson/util/DescribableList.java
@@ -50,6 +50,7 @@
 import jenkins.model.DependencyDeclarer;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Persisted list of {@link Describable}s with some operations specific
@@ -167,7 +168,7 @@ public Map<D, T> toMap() {
      * @param json
      *      Structured form data that includes the data for nested descriptor list.
      */
-    public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descriptor<T>> descriptors) throws FormException, IOException {
+    public void rebuild(StaplerRequest2 req, JSONObject json, List<? extends Descriptor<T>> descriptors) throws FormException, IOException {
         List<T> newList = new ArrayList<>();
 
         for (Descriptor<T> d : descriptors) {
@@ -193,9 +194,17 @@ public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descript
         replaceBy(newList);
     }
 
+    /**
+     * @deprecated use {@link #rebuild(StaplerRequest2, JSONObject, List)}
+     */
+    @Deprecated
+    public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descriptor<T>> descriptors) throws FormException, IOException {
+        rebuild(StaplerRequest.toStaplerRequest2(req), json, descriptors);
+    }
+
     /**
      * @deprecated as of 1.271
-     *      Use {@link #rebuild(StaplerRequest, JSONObject, List)} instead.
+     *      Use {@link #rebuild(StaplerRequest2, JSONObject, List)} instead.
      */
     @Deprecated
     public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descriptor<T>> descriptors, String prefix) throws FormException, IOException {
@@ -210,10 +219,18 @@ public void rebuild(StaplerRequest req, JSONObject json, List<? extends Descript
      * is allowed to create multiple instances of the same descriptor. Order is also
      * significant.
      */
-    public void rebuildHetero(StaplerRequest req, JSONObject formData, Collection<? extends Descriptor<T>> descriptors, String key) throws FormException, IOException {
+    public void rebuildHetero(StaplerRequest2 req, JSONObject formData, Collection<? extends Descriptor<T>> descriptors, String key) throws FormException, IOException {
         replaceBy(Descriptor.newInstancesFromHeteroList(req, formData, key, descriptors));
     }
 
+    /**
+     * @deprecated use {@link #rebuildHetero(StaplerRequest2, JSONObject, Collection, String)}
+     */
+    @Deprecated
+    public void rebuildHetero(StaplerRequest req, JSONObject formData, Collection<? extends Descriptor<T>> descriptors, String key) throws FormException, IOException {
+        rebuildHetero(StaplerRequest.toStaplerRequest2(req), formData, descriptors, key);
+    }
+
     /**
      * Picks up {@link DependencyDeclarer}s and allow it to build dependencies.
      */
diff --git a/core/src/main/java/hudson/util/DescriptorList.java b/core/src/main/java/hudson/util/DescriptorList.java
index 94f105892cd8..c9b515d85c4e 100644
--- a/core/src/main/java/hudson/util/DescriptorList.java
+++ b/core/src/main/java/hudson/util/DescriptorList.java
@@ -160,7 +160,7 @@ public T newInstanceFromRadioList(JSONObject config) throws FormException {
         if (config.isNullObject())
             return null;    // none was selected
         int idx = config.getInt("value");
-        return get(idx).newInstance(Stapler.getCurrentRequest(), config);
+        return get(idx).newInstance(Stapler.getCurrentRequest2(), config);
     }
 
     /**
diff --git a/core/src/main/java/hudson/util/ErrorObject.java b/core/src/main/java/hudson/util/ErrorObject.java
index 2f9f39ec8f19..48e1106b35f1 100644
--- a/core/src/main/java/hudson/util/ErrorObject.java
+++ b/core/src/main/java/hudson/util/ErrorObject.java
@@ -24,13 +24,13 @@
 
 package hudson.util;
 
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 
 import hudson.Functions;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Basis for error model objects.
@@ -52,7 +52,7 @@ public String getStackTraceString() {
         return Functions.printThrowable(this);
     }
 
-    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         rsp.setStatus(SC_SERVICE_UNAVAILABLE);
         req.getView(this, "index.jelly").forward(req, rsp);
     }
diff --git a/core/src/main/java/hudson/util/FormApply.java b/core/src/main/java/hudson/util/FormApply.java
index 8a1db5bebe4e..dc5e4d64df9b 100644
--- a/core/src/main/java/hudson/util/FormApply.java
+++ b/core/src/main/java/hudson/util/FormApply.java
@@ -24,11 +24,12 @@
 
 package hudson.util;
 
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.kohsuke.stapler.HttpResponses.HttpResponseException;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Server-side code related to the {@code <f:apply>} button.
@@ -47,7 +48,7 @@ public class FormApply {
     public static HttpResponseException success(final String destination) {
         return new HttpResponseException() {
             @Override
-            public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                 if (isApply(req)) {
                     // if the submission is via 'apply', show a response in the notification bar
                     applyResponse("notificationBar.show('" + Messages.HttpResponses_Saved() + "',notificationBar.SUCCESS)")
@@ -61,11 +62,21 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod
 
     /**
      * Is this submission from the "apply" button?
+     *
+     * @since TODO
      */
-    public static boolean isApply(StaplerRequest req) {
+    public static boolean isApply(StaplerRequest2 req) {
         return Boolean.parseBoolean(req.getParameter("core:apply"));
     }
 
+    /**
+     * @deprecated use {@link #isApply(StaplerRequest2)}
+     */
+    @Deprecated
+    public static boolean isApply(StaplerRequest req) {
+        return isApply(StaplerRequest.toStaplerRequest2(req));
+    }
+
     /**
      * Generates the response for the asynchronous background form submission (AKA the Apply button.)
      * <p>
@@ -75,7 +86,7 @@ public static boolean isApply(StaplerRequest req) {
     public static HttpResponseException applyResponse(final String script) {
         return new HttpResponseException() {
             @Override
-            public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                 rsp.setContentType("text/html;charset=UTF-8");
                 rsp.getWriter().println("<html><body><script>" +
                         "window.applyCompletionHandler = function (w) {" +
diff --git a/core/src/main/java/hudson/util/FormFillFailure.java b/core/src/main/java/hudson/util/FormFillFailure.java
index 5ebd0d5a31e6..946d3f8997cf 100644
--- a/core/src/main/java/hudson/util/FormFillFailure.java
+++ b/core/src/main/java/hudson/util/FormFillFailure.java
@@ -27,14 +27,14 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Functions;
 import hudson.Util;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Locale;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Represents a failure in a form field doFillXYZ method.
@@ -132,7 +132,7 @@ private static FormFillFailure _errorWithMarkup(@NonNull final String message, f
         return new FormFillFailure(kind, message) {
             @Override
             public String renderHtml() {
-                StaplerRequest req = Stapler.getCurrentRequest();
+                StaplerRequest2 req = Stapler.getCurrentRequest2();
                 if (req == null) { // being called from some other context
                     return message;
                 }
@@ -182,7 +182,7 @@ private FormFillFailure(FormValidation.Kind kind, String message) {
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node)
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node)
             throws IOException, ServletException {
         rsp.setContentType("text/html;charset=UTF-8");
         rsp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
diff --git a/core/src/main/java/hudson/util/FormValidation.java b/core/src/main/java/hudson/util/FormValidation.java
index c1cfda5ef6a9..f61b95883782 100644
--- a/core/src/main/java/hudson/util/FormValidation.java
+++ b/core/src/main/java/hudson/util/FormValidation.java
@@ -40,6 +40,7 @@
 import hudson.model.Descriptor;
 import hudson.tasks.Builder;
 import hudson.util.ReflectionUtils.Parameter;
+import jakarta.servlet.ServletException;
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -58,21 +59,20 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.stream.Stream;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Represents the result of the form field validation.
  *
  * <p>
  * Use one of the factory methods to create an instance, then return it from your {@code doCheckXyz}
- * method. (Via {@link HttpResponse}, the returned object will render the result into {@link StaplerResponse}.)
+ * method. (Via {@link HttpResponse}, the returned object will render the result into {@link StaplerResponse2}.)
  * This way of designing form field validation allows you to reuse {@code doCheckXyz()} methods
  * programmatically as well (by using {@link #kind}.
  *
@@ -274,7 +274,7 @@ private static FormValidation _errorWithMarkup(final String message, final Kind
         return new FormValidation(kind, message) {
             @Override
             public String renderHtml() {
-                StaplerRequest req = Stapler.getCurrentRequest();
+                StaplerRequest2 req = Stapler.getCurrentRequest2();
                 if (req == null) { // being called from some other context
                     return message;
                 }
@@ -551,7 +551,7 @@ protected boolean findText(BufferedReader in, String literal) throws IOException
          * @param url
          *      Pass in the URL that was connected. Used for error diagnosis.
          */
-        protected FormValidation handleIOException(String url, IOException e) throws IOException, ServletException {
+        protected FormValidation handleIOException(String url, IOException e) throws IOException {
             // any invalid URL comes here
             if (e.getMessage().equals(url))
                 // Sun JRE (and probably others too) often return just the URL in the error.
@@ -580,7 +580,7 @@ private String getCharset(URLConnection con) {
          * Implement the actual form validation logic, by using other convenience methods defined in this class.
          * If you are not using any of those, you don't need to extend from this class.
          */
-        protected abstract FormValidation check() throws IOException, ServletException;
+        protected abstract FormValidation check() throws IOException;
     }
 
 
@@ -600,7 +600,7 @@ private FormValidation(Kind kind, String message) {
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         respond(rsp, renderHtml());
     }
 
@@ -609,7 +609,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod
     /**
      * Sends out an arbitrary HTML fragment as the output.
      */
-    protected void respond(StaplerResponse rsp, String html) throws IOException, ServletException {
+    protected void respond(StaplerResponse2 rsp, String html) throws IOException, ServletException {
         rsp.setContentType("text/html;charset=UTF-8");
         if (APPLY_CONTENT_SECURITY_POLICY_HEADERS) {
             for (String header : new String[]{"Content-Security-Policy", "X-WebKit-CSP", "X-Content-Security-Policy"}) {
diff --git a/core/src/main/java/hudson/util/Graph.java b/core/src/main/java/hudson/util/Graph.java
index a543e18cd6d7..6e4ef6c59515 100644
--- a/core/src/main/java/hudson/util/Graph.java
+++ b/core/src/main/java/hudson/util/Graph.java
@@ -27,6 +27,8 @@
 import com.google.common.annotations.VisibleForTesting;
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
+import hudson.Util;
+import jakarta.servlet.ServletOutputStream;
 import java.awt.Color;
 import java.awt.Dimension;
 import java.awt.HeadlessException;
@@ -34,7 +36,7 @@
 import java.io.IOException;
 import java.util.Calendar;
 import javax.imageio.ImageIO;
-import javax.servlet.ServletOutputStream;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import org.jfree.chart.ChartRenderingInfo;
 import org.jfree.chart.ChartUtilities;
@@ -43,7 +45,9 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * A JFreeChart-generated graph that's bound to UI.
@@ -91,7 +95,7 @@ protected Graph(Calendar timestamp, int defaultWidth, int defaultHeight) {
      */
     protected abstract JFreeChart createGraph();
 
-    private BufferedImage render(StaplerRequest req, ChartRenderingInfo info) {
+    private BufferedImage render(StaplerRequest2 req, ChartRenderingInfo info) {
         String w = req.getParameter("width");
         if (w == null) {
             w = String.valueOf(defaultWidth);
@@ -147,8 +151,27 @@ public static Dimension safeDimension(int width, int height, int defaultWidth, i
 
     /**
      * Renders a graph.
+     *
+     * @since TODO
      */
+    public void doPng(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
+        if (Util.isOverridden(Graph.class, getClass(), "doPng", StaplerRequest.class, StaplerResponse.class)) {
+            doPng(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            doPngImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doPng(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
     public void doPng(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        doPngImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doPngImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.checkIfModified(timestamp, rsp)) return;
 
         try {
@@ -201,8 +224,27 @@ public void doPng(StaplerRequest req, StaplerResponse rsp) throws IOException {
 
     /**
      * Renders a clickable map.
+     *
+     * @since TODO
      */
+    public void doMap(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
+        if (Util.isOverridden(Graph.class, getClass(), "doMap", StaplerRequest.class, StaplerResponse.class)) {
+            doMap(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+        } else {
+            doMapImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doMap(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
     public void doMap(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        doMapImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+    }
+
+    private void doMapImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.checkIfModified(timestamp, rsp)) return;
 
         ChartRenderingInfo info = new ChartRenderingInfo();
diff --git a/core/src/main/java/hudson/util/HttpResponses.java b/core/src/main/java/hudson/util/HttpResponses.java
index 1e24d8216550..a1e91d2374fa 100644
--- a/core/src/main/java/hudson/util/HttpResponses.java
+++ b/core/src/main/java/hudson/util/HttpResponses.java
@@ -25,16 +25,16 @@
 package hudson.util;
 
 import edu.umd.cs.findbugs.annotations.NonNull;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.Map;
-import javax.servlet.ServletException;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Various {@link HttpResponse} implementations.
@@ -204,7 +204,7 @@ static class JSONObjectResponse implements HttpResponse {
         }
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             byte[] bytes = jsonObject.toString().getBytes(StandardCharsets.UTF_8);
             rsp.setContentType("application/json; charset=UTF-8");
             rsp.setContentLength(bytes.length);
diff --git a/core/src/main/java/hudson/util/HudsonIsLoading.java b/core/src/main/java/hudson/util/HudsonIsLoading.java
index 6e6964fbed17..1f3782dfe155 100644
--- a/core/src/main/java/hudson/util/HudsonIsLoading.java
+++ b/core/src/main/java/hudson/util/HudsonIsLoading.java
@@ -24,13 +24,13 @@
 
 package hudson.util;
 
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Model object used to display "Jenkins is loading data".
@@ -41,7 +41,7 @@
  * @author Kohsuke Kawaguchi
  */
 public class HudsonIsLoading {
-    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         rsp.setStatus(SC_SERVICE_UNAVAILABLE);
         req.getView(this, "index.jelly").forward(req, rsp);
     }
diff --git a/core/src/main/java/hudson/util/HudsonIsRestarting.java b/core/src/main/java/hudson/util/HudsonIsRestarting.java
index 4e76657a9fa4..ba0a635b3963 100644
--- a/core/src/main/java/hudson/util/HudsonIsRestarting.java
+++ b/core/src/main/java/hudson/util/HudsonIsRestarting.java
@@ -24,13 +24,13 @@
 
 package hudson.util;
 
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Model object used to display "Hudson is restarting".
@@ -55,7 +55,7 @@ public HudsonIsRestarting() {
         this.safeRestart = false;
     }
 
-    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         rsp.setStatus(SC_SERVICE_UNAVAILABLE);
         req.getView(this, "index.jelly").forward(req, rsp);
     }
diff --git a/core/src/main/java/hudson/util/ListBoxModel.java b/core/src/main/java/hudson/util/ListBoxModel.java
index cf889493acc4..c97ed0f431e7 100644
--- a/core/src/main/java/hudson/util/ListBoxModel.java
+++ b/core/src/main/java/hudson/util/ListBoxModel.java
@@ -25,15 +25,19 @@
 package hudson.util;
 
 import edu.umd.cs.findbugs.annotations.NonNull;
+import hudson.Util;
 import hudson.model.ModelObject;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import javax.servlet.ServletException;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.export.Flavor;
@@ -166,12 +170,39 @@ public ListBoxModel add(@NonNull String nameAndValue) {
         return this;
     }
 
-    public void writeTo(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    /**
+     * @since TODO
+     */
+    public void writeTo(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
+        if (Util.isOverridden(ListBoxModel.class, getClass(), "writeTo", StaplerRequest.class, StaplerResponse.class)) {
+            try {
+                writeTo(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp));
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            writeToImpl(req, rsp);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #writeTo(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    public void writeTo(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            writeToImpl(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    private void writeToImpl(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.serveExposedBean(req, this, Flavor.JSON);
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         writeTo(req, rsp);
     }
 
diff --git a/core/src/main/java/hudson/util/MultipartFormDataParser.java b/core/src/main/java/hudson/util/MultipartFormDataParser.java
index f173cff9802b..47e880486fba 100644
--- a/core/src/main/java/hudson/util/MultipartFormDataParser.java
+++ b/core/src/main/java/hudson/util/MultipartFormDataParser.java
@@ -25,14 +25,15 @@
 package hudson.util;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
+import io.jenkins.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
 import java.io.File;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.nio.file.Files;
 import java.util.HashMap;
 import java.util.Map;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
 import org.apache.commons.fileupload2.core.DiskFileItem;
 import org.apache.commons.fileupload2.core.DiskFileItemFactory;
 import org.apache.commons.fileupload2.core.FileItem;
@@ -40,8 +41,8 @@
 import org.apache.commons.fileupload2.core.FileUploadException;
 import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
 import org.apache.commons.fileupload2.core.FileUploadSizeException;
-import org.apache.commons.fileupload2.javax.JavaxServletDiskFileUpload;
-import org.apache.commons.fileupload2.javax.JavaxServletFileUpload;
+import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletDiskFileUpload;
+import org.apache.commons.fileupload2.jakarta.servlet5.JakartaServletFileUpload;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 
@@ -56,7 +57,7 @@ public class MultipartFormDataParser implements AutoCloseable {
 
     /**
      * Limits the number of form fields that can be processed in one multipart/form-data request.
-     * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileCountMax(long)}.
+     * Used to set {@link org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload#setFileCountMax(long)}.
      * Despite the name, this applies to all form fields, not just actual file attachments.
      * Set to {@code -1} to disable limits.
      */
@@ -64,7 +65,7 @@ public class MultipartFormDataParser implements AutoCloseable {
 
     /**
      * Limits the size (in bytes) of individual fields that can be processed in one multipart/form-data request.
-     * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setFileSizeMax(long)}.
+     * Used to set {@link org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload#setFileSizeMax(long)}.
      * Despite the name, this applies to all form fields, not just actual file attachments.
      * Set to {@code -1} to disable limits.
      */
@@ -72,7 +73,7 @@ public class MultipartFormDataParser implements AutoCloseable {
 
     /**
      * Limits the total request size (in bytes) that can be processed in one multipart/form-data request.
-     * Used to set {@link org.apache.commons.fileupload2.javax.JavaxServletFileUpload#setSizeMax(long)}.
+     * Used to set {@link org.apache.commons.fileupload2.jakarta.JakartaServletFileUpload#setSizeMax(long)}.
      * Set to {@code -1} to disable limits.
      */
     private static /* nonfinal for Jenkins script console */ long FILEUPLOAD_MAX_SIZE = Long.getLong(MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_SIZE", -1);
@@ -86,7 +87,7 @@ public MultipartFormDataParser(HttpServletRequest request, int maxParts, long ma
             throw new ServletException("Error creating temporary directory", e);
         }
         tmpDir.deleteOnExit();
-        JavaxServletFileUpload<DiskFileItem, DiskFileItemFactory> upload = new JavaxServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get());
+        JakartaServletFileUpload<DiskFileItem, DiskFileItemFactory> upload = new JakartaServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get());
         upload.setFileCountMax(maxParts);
         upload.setFileSizeMax(maxPartSize);
         upload.setSizeMax(maxSize);
@@ -116,6 +117,39 @@ public MultipartFormDataParser(HttpServletRequest request) throws ServletExcepti
         this(request, FILEUPLOAD_MAX_FILES, FILEUPLOAD_MAX_FILE_SIZE, FILEUPLOAD_MAX_SIZE);
     }
 
+    /**
+     * @deprecated use {@link #MultipartFormDataParser(HttpServletRequest)}
+     */
+    @Deprecated
+    public MultipartFormDataParser(javax.servlet.http.HttpServletRequest request) throws javax.servlet.ServletException {
+        File tmpDir;
+        try {
+            tmpDir = Files.createTempDirectory("jenkins-multipart-uploads").toFile();
+        } catch (IOException e) {
+            throw new javax.servlet.ServletException("Error creating temporary directory", e);
+        }
+        tmpDir.deleteOnExit();
+        JakartaServletFileUpload<DiskFileItem, DiskFileItemFactory> upload = new JakartaServletDiskFileUpload(DiskFileItemFactory.builder().setFile(tmpDir).get());
+        upload.setFileCountMax(FILEUPLOAD_MAX_FILES);
+        upload.setFileSizeMax(FILEUPLOAD_MAX_FILE_SIZE);
+        upload.setSizeMax(FILEUPLOAD_MAX_SIZE);
+        try {
+            for (FileItem fi : upload.parseRequest(HttpServletRequestWrapper.toJakartaHttpServletRequest(request)))
+                byName.put(fi.getFieldName(), fi);
+        } catch (FileUploadFileCountLimitException e) {
+            throw new javax.servlet.ServletException("File upload field count limit exceeded. Consider setting the Java system property "
+                    + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_FILES to a value greater than " + FILEUPLOAD_MAX_FILES + ", or to -1 to disable this limit.", e);
+        } catch (FileUploadByteCountLimitException e) {
+            throw new javax.servlet.ServletException("File upload field size limit exceeded. Consider setting the Java system property "
+                    + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_FILE_SIZE to a value greater than " + FILEUPLOAD_MAX_FILE_SIZE + ", or to -1 to disable this limit.", e);
+        } catch (FileUploadSizeException e) {
+            throw new javax.servlet.ServletException("File upload total size limit exceeded. Consider setting the Java system property "
+                    + MultipartFormDataParser.class.getName() + ".FILEUPLOAD_MAX_SIZE to a value greater than " + FILEUPLOAD_MAX_SIZE + ", or to -1 to disable this limit.", e);
+        } catch (FileUploadException e) {
+            throw new javax.servlet.ServletException(e);
+        }
+    }
+
     public String get(String key) {
         FileItem fi = byName.get(key);
         if (fi == null)    return null;
diff --git a/core/src/main/java/hudson/util/PluginServletFilter.java b/core/src/main/java/hudson/util/PluginServletFilter.java
index 037b7010d51a..bb4ecfc18d9b 100644
--- a/core/src/main/java/hudson/util/PluginServletFilter.java
+++ b/core/src/main/java/hudson/util/PluginServletFilter.java
@@ -27,6 +27,15 @@
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.ExtensionPoint;
 import hudson.security.SecurityRealm;
+import io.jenkins.servlet.FilterWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -35,17 +44,11 @@
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.util.HttpServletFilter;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * Servlet {@link Filter} that chains multiple {@link Filter}s, provided by plugins
@@ -60,7 +63,7 @@
  *
  * @see SecurityRealm
  */
-public final class PluginServletFilter implements Filter, ExtensionPoint {
+public final class PluginServletFilter implements CompatibleFilter, ExtensionPoint {
     private final List<Filter> list = new CopyOnWriteArrayList<>();
 
     private /*almost final*/ FilterConfig config;
@@ -101,13 +104,15 @@ public void init(FilterConfig config) throws ServletException {
      * Dynamically register a new filter.
      * May be paired with {@link #removeFilter}.
      * <p>For most purposes you can instead use {@link HttpServletFilter}.
+     *
+     * @since TODO
      */
     public static void addFilter(Filter filter) throws ServletException {
         Jenkins j = Jenkins.getInstanceOrNull();
 
         PluginServletFilter container = null;
         if (j != null) {
-            container = getInstance(j.servletContext);
+            container = getInstance(j.getServletContext());
         }
         // https://marvelution.atlassian.net/browse/JJI-188
         if (j == null || container == null) {
@@ -120,17 +125,29 @@ public static void addFilter(Filter filter) throws ServletException {
         }
     }
 
+    /**
+     * @deprecated use {@link #addFilter(Filter)}
+     */
+    @Deprecated
+    public static void addFilter(javax.servlet.Filter filter) throws javax.servlet.ServletException {
+        try {
+            addFilter(FilterWrapper.toJakartaFilter(filter));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Checks whether the given filter is already registered in the chain.
      * @param filter the filter to check.
      * @return true if the filter is already registered in the chain.
-     * @since 2.94
+     * @since TODO
      */
     public static boolean hasFilter(Filter filter) {
         Jenkins j = Jenkins.getInstanceOrNull();
         PluginServletFilter container = null;
         if (j != null) {
-            container = getInstance(j.servletContext);
+            container = getInstance(j.getServletContext());
         }
         if (j == null || container == null) {
             return LEGACY.contains(filter);
@@ -139,12 +156,36 @@ public static boolean hasFilter(Filter filter) {
         }
     }
 
+    /**
+     * @deprecated use {@link #hasFilter(Filter)}
+     * @since 2.94
+     */
+    @Deprecated
+    public static boolean hasFilter(javax.servlet.Filter filter) {
+        return hasFilter(FilterWrapper.toJakartaFilter(filter));
+    }
+
+    /**
+     * @since TODO
+     */
     public static void removeFilter(Filter filter) throws ServletException {
         Jenkins j = Jenkins.getInstanceOrNull();
-        if (j == null || getInstance(j.servletContext) == null) {
+        if (j == null || getInstance(j.getServletContext()) == null) {
             LEGACY.remove(filter);
         } else {
-            getInstance(j.servletContext).list.remove(filter);
+            getInstance(j.getServletContext()).list.remove(filter);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #removeFilter(Filter)}
+     */
+    @Deprecated
+    public static void removeFilter(javax.servlet.Filter filter) throws javax.servlet.ServletException {
+        try {
+            removeFilter(FilterWrapper.toJakartaFilter(filter));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
         }
     }
 
@@ -180,7 +221,7 @@ public static void cleanUp() {
         if (jenkins == null) {
             return;
         }
-        PluginServletFilter instance = getInstance(jenkins.servletContext);
+        PluginServletFilter instance = getInstance(jenkins.getServletContext());
         if (instance != null) {
             // While we could rely on the current implementation of list being a CopyOnWriteArrayList
             // safer to just take an explicit copy of the list and operate on the copy
diff --git a/core/src/main/java/hudson/util/QueryParameterMap.java b/core/src/main/java/hudson/util/QueryParameterMap.java
index ba3ce8c0d00a..fc846c6fc73b 100644
--- a/core/src/main/java/hudson/util/QueryParameterMap.java
+++ b/core/src/main/java/hudson/util/QueryParameterMap.java
@@ -24,6 +24,7 @@
 
 package hudson.util;
 
+import jakarta.servlet.http.HttpServletRequest;
 import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
@@ -31,7 +32,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
 
 /**
  * Parses the query string of the URL into a key/value pair.
@@ -70,6 +70,14 @@ public QueryParameterMap(HttpServletRequest req) {
         this(req.getQueryString());
     }
 
+    /**
+     * @deprecated use {@link #QueryParameterMap(HttpServletRequest)}
+     */
+    @Deprecated
+    public QueryParameterMap(javax.servlet.http.HttpServletRequest req) {
+        this(req.getQueryString());
+    }
+
     public String get(String name) {
         List<String> v = store.get(name);
         return v != null ? v.get(0) : null;
diff --git a/core/src/main/java/hudson/util/RemotingDiagnostics.java b/core/src/main/java/hudson/util/RemotingDiagnostics.java
index 06a42beee69d..c18e056e428b 100644
--- a/core/src/main/java/hudson/util/RemotingDiagnostics.java
+++ b/core/src/main/java/hudson/util/RemotingDiagnostics.java
@@ -59,8 +59,8 @@
 import org.codehaus.groovy.control.customizers.ImportCustomizer;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
@@ -211,7 +211,7 @@ public HeapDump(AccessControlled owner, VirtualChannel channel) {
 
         @WebMethod(name = "heapdump.hprof")
         @RequirePOST
-        public void doHeapDump(StaplerRequest req, StaplerResponse rsp) throws IOException, InterruptedException {
+        public void doHeapDump(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, InterruptedException {
             owner.checkPermission(Jenkins.ADMINISTER);
             rsp.setContentType("application/octet-stream");
 
diff --git a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java
index b60939aae5ee..81927927c9e6 100644
--- a/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java
+++ b/core/src/main/java/hudson/views/GlobalDefaultViewConfiguration.java
@@ -30,7 +30,7 @@
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Adds the default view configuration to the system config page.
@@ -40,7 +40,7 @@
 @Extension(ordinal = 300) @Symbol("defaultView")
 public class GlobalDefaultViewConfiguration extends GlobalConfiguration {
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         // for compatibility reasons, the actual value is stored in Jenkins
         Jenkins j = Jenkins.get();
         if (json.has("primaryView")) {
diff --git a/core/src/main/java/hudson/views/ListViewColumn.java b/core/src/main/java/hudson/views/ListViewColumn.java
index 91e93e2145da..423094af51b3 100644
--- a/core/src/main/java/hudson/views/ListViewColumn.java
+++ b/core/src/main/java/hudson/views/ListViewColumn.java
@@ -42,6 +42,7 @@
 import java.util.logging.Logger;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.export.Exported;
 
 /**
@@ -162,7 +163,7 @@ private static List<ListViewColumn> createDefaultInitialColumnList(List<Descript
                         continue;   // skip this
                     }
                 }
-                ListViewColumn lvc = d.newInstance(null, emptyJSON);
+                ListViewColumn lvc = d.newInstance((StaplerRequest2) null, emptyJSON);
                 if (!lvc.shownByDefault()) {
                     continue; // skip this
                 }
diff --git a/core/src/main/java/hudson/views/MyViewsTabBar.java b/core/src/main/java/hudson/views/MyViewsTabBar.java
index bc73ba9abd9d..f6fc15745b9b 100644
--- a/core/src/main/java/hudson/views/MyViewsTabBar.java
+++ b/core/src/main/java/hudson/views/MyViewsTabBar.java
@@ -41,7 +41,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Extension point for adding a MyViewsTabBar header to Projects {@link MyViewsProperty}.
@@ -100,7 +100,7 @@ public MyViewsTabBar getMyViewsTabBar() {
         }
 
         @Override
-        public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+        public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
             // for compatibility reasons, the actual value is stored in Jenkins
             Jenkins j = Jenkins.get();
 
diff --git a/core/src/main/java/hudson/views/ViewsTabBar.java b/core/src/main/java/hudson/views/ViewsTabBar.java
index 195f72104aba..a7d133e78213 100644
--- a/core/src/main/java/hudson/views/ViewsTabBar.java
+++ b/core/src/main/java/hudson/views/ViewsTabBar.java
@@ -41,7 +41,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Extension point for adding a ViewsTabBar header to Projects {@link ListView}.
@@ -100,7 +100,7 @@ public ViewsTabBar getViewsTabBar() {
         }
 
         @Override
-        public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+        public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
             // for compatibility reasons, the actual value is stored in Jenkins
             Jenkins j = Jenkins.get();
 
diff --git a/core/src/main/java/hudson/widgets/HistoryWidget.java b/core/src/main/java/hudson/widgets/HistoryWidget.java
index 1c291d1a48ff..44f6de67ee6f 100644
--- a/core/src/main/java/hudson/widgets/HistoryWidget.java
+++ b/core/src/main/java/hudson/widgets/HistoryWidget.java
@@ -33,13 +33,13 @@
 import hudson.model.Queue;
 import hudson.model.Run;
 import hudson.util.AlternativeUiTextProvider;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.util.SystemProperties;
 import jenkins.widgets.HistoryPageEntry;
 import jenkins.widgets.HistoryPageFilter;
@@ -49,8 +49,8 @@
 import org.kohsuke.accmod.restrictions.DoNotUse;
 import org.kohsuke.stapler.Header;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Displays the history of records (normally {@link Run}s) on the side panel.
@@ -103,7 +103,7 @@ public class HistoryWidget<O extends ModelObject, T> extends Widget {
      *      The parent model object that owns this widget.
      */
     public HistoryWidget(O owner, Iterable<T> baseList, Adapter<? super T> adapter) {
-        StaplerRequest currentRequest = Stapler.getCurrentRequest();
+        StaplerRequest2 currentRequest = Stapler.getCurrentRequest2();
         this.adapter = adapter;
         this.baseList = baseList;
         this.baseUrl = Functions.getNearestAncestorUrl(currentRequest, owner);
@@ -234,7 +234,7 @@ public void setTrimmed(boolean trimmed) {
      *      The build 'number' to fetch. This is string because various variants
      *      uses non-numbers as the build key.
      */
-    public void doAjax(StaplerRequest req, StaplerResponse rsp,
+    public void doAjax(StaplerRequest2 req, StaplerResponse2 rsp,
           @Header("n") String n) throws IOException, ServletException {
 
         rsp.setContentType("text/html;charset=UTF-8");
@@ -298,7 +298,7 @@ public interface Adapter<T> {
         String getNextKey(String key);
     }
 
-    private Long getPagingParam(@CheckForNull StaplerRequest currentRequest, @CheckForNull String name) {
+    private Long getPagingParam(@CheckForNull StaplerRequest2 currentRequest, @CheckForNull String name) {
         if (currentRequest == null || name == null) {
             return null;
         }
diff --git a/core/src/main/java/hudson/widgets/RenderOnDemandClosure.java b/core/src/main/java/hudson/widgets/RenderOnDemandClosure.java
index 9092526f109b..bd3a5518a75b 100644
--- a/core/src/main/java/hudson/widgets/RenderOnDemandClosure.java
+++ b/core/src/main/java/hudson/widgets/RenderOnDemandClosure.java
@@ -27,6 +27,7 @@
 import hudson.Util;
 import hudson.model.Descriptor;
 import hudson.util.PackedMap;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -35,13 +36,12 @@
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import org.apache.commons.jelly.JellyContext;
 import org.apache.commons.jelly.JellyTagException;
 import org.apache.commons.jelly.Script;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.bind.JavaScriptMethod;
 import org.kohsuke.stapler.framework.adjunct.AdjunctsInPage;
 import org.kohsuke.stapler.jelly.DefaultScriptInvoker;
@@ -95,12 +95,12 @@ public RenderOnDemandClosure(JellyContext context, String attributesToCapture) {
     public HttpResponse render() {
         return new HttpResponse() {
             @Override
-            public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
                 req.getWebApp().getDispatchValidator().allowDispatch(req, rsp);
                 try {
                     new DefaultScriptInvoker() {
                         @Override
-                        protected JellyContext createContext(StaplerRequest req, StaplerResponse rsp, Script script, Object it) {
+                        protected JellyContext createContext(StaplerRequest2 req, StaplerResponse2 rsp, Script script, Object it) {
                             JellyContext context = super.createContext(req, rsp, script, it);
                             for (int i = bodyStack.length - 1; i > 0; i--) { // exclude bodyStack[0]
                                 context = new JellyContext(context);
@@ -115,7 +115,7 @@ protected JellyContext createContext(StaplerRequest req, StaplerResponse rsp, Sc
                         }
 
                         @Override
-                        protected void exportVariables(StaplerRequest req, StaplerResponse rsp, Script script, Object it, JellyContext context) {
+                        protected void exportVariables(StaplerRequest2 req, StaplerResponse2 rsp, Script script, Object it, JellyContext context) {
                             super.exportVariables(req, rsp, script, it, context);
                             context.setVariables(variables);
                             req.setAttribute("currentDescriptorByNameUrl", currentDescriptorByNameUrl);
diff --git a/core/src/main/java/jenkins/ErrorAttributeFilter.java b/core/src/main/java/jenkins/ErrorAttributeFilter.java
index be67bdab7588..f3dfe05f4f89 100644
--- a/core/src/main/java/jenkins/ErrorAttributeFilter.java
+++ b/core/src/main/java/jenkins/ErrorAttributeFilter.java
@@ -1,24 +1,24 @@
 package jenkins;
 
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.springframework.security.core.Authentication;
 
 /**
  * Record the current user authentication for later impersonation if the response is 404 Not Found.
  *
- * @see Jenkins#generateNotFoundResponse(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse)
+ * @see Jenkins#generateNotFoundResponse(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)
  */
 @Restricted(NoExternalUse.class)
-public class ErrorAttributeFilter implements Filter {
+public class ErrorAttributeFilter implements CompatibleFilter {
 
     public static final String USER_ATTRIBUTE = "jenkins.ErrorAttributeFilter.user";
 
diff --git a/core/src/main/java/jenkins/I18n.java b/core/src/main/java/jenkins/I18n.java
index d9b234b0d2c7..23fa2a4417eb 100644
--- a/core/src/main/java/jenkins/I18n.java
+++ b/core/src/main/java/jenkins/I18n.java
@@ -32,7 +32,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Internationalization REST (ish) API.
@@ -74,7 +74,7 @@ public String getUrlName() {
      * @param request The request.
      * @return The JSON response.
      */
-    public HttpResponse doResourceBundle(StaplerRequest request) {
+    public HttpResponse doResourceBundle(StaplerRequest2 request) {
         String baseName = request.getParameter("baseName");
 
         if (baseName == null) {
diff --git a/core/src/main/java/jenkins/JenkinsHttpSessionListener.java b/core/src/main/java/jenkins/JenkinsHttpSessionListener.java
index 4d2c7960b25b..9a9c0b9efba3 100644
--- a/core/src/main/java/jenkins/JenkinsHttpSessionListener.java
+++ b/core/src/main/java/jenkins/JenkinsHttpSessionListener.java
@@ -24,9 +24,9 @@
 
 package jenkins;
 
+import jakarta.servlet.http.HttpSessionEvent;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.http.HttpSessionEvent;
 import jenkins.util.HttpSessionListener;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
@@ -37,7 +37,7 @@
  * @author <a href="mailto:tom.fennelly@gmail.com">tom.fennelly@gmail.com</a>
  */
 @Restricted(NoExternalUse.class)
-public final class JenkinsHttpSessionListener implements javax.servlet.http.HttpSessionListener {
+public final class JenkinsHttpSessionListener implements jakarta.servlet.http.HttpSessionListener {
 
     // TODO: Seems like classes like this should live in the /war/src/java
     // But that applies to a number of other classes too and it has never happened, so will
diff --git a/core/src/main/java/jenkins/agents/CloudSet.java b/core/src/main/java/jenkins/agents/CloudSet.java
index 163556a001d1..adbbf51de4e4 100644
--- a/core/src/main/java/jenkins/agents/CloudSet.java
+++ b/core/src/main/java/jenkins/agents/CloudSet.java
@@ -36,6 +36,7 @@
 import hudson.model.UpdateCenter;
 import hudson.slaves.Cloud;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -45,7 +46,6 @@
 import java.util.List;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import jenkins.model.ModelObjectWithChildren;
 import jenkins.model.ModelObjectWithContextMenu;
@@ -56,7 +56,8 @@
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
 
@@ -102,7 +103,7 @@ public String getSearchUrl() {
 
     @SuppressWarnings("unused") // stapler
     @Restricted(DoNotUse.class) // stapler
-    public String getCloudUrl(StaplerRequest request, Jenkins jenkins, Cloud cloud) {
+    public String getCloudUrl(StaplerRequest2 request, Jenkins jenkins, Cloud cloud) {
         String context = Functions.getNearestAncestorUrl(request, jenkins);
         if (Jenkins.get().getCloud(cloud.name) != cloud) { // this cloud is not the first occurrence with this name
             return context + "/cloud/cloudByIndex/" + getClouds().indexOf(cloud) + "/";
@@ -111,6 +112,16 @@ public String getCloudUrl(StaplerRequest request, Jenkins jenkins, Cloud cloud)
         }
     }
 
+    /**
+     * @deprecated use {@link #getCloudUrl(StaplerRequest2, Jenkins, Cloud)}
+     */
+    @Deprecated
+    @SuppressWarnings("unused") // stapler
+    @Restricted(DoNotUse.class) // stapler
+    public String getCloudUrl(StaplerRequest request, Jenkins jenkins, Cloud cloud) {
+        return getCloudUrl(StaplerRequest.toStaplerRequest2(request), jenkins, cloud);
+    }
+
     @SuppressWarnings("unused") // stapler
     @Restricted(DoNotUse.class) // stapler
     public Cloud getCloudByIndex(int index) {
@@ -128,13 +139,13 @@ public String getCloudUpdateCenterCategoryLabel() {
     }
 
     @Override
-    public ModelObjectWithContextMenu.ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ModelObjectWithContextMenu.ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ModelObjectWithContextMenu.ContextMenu m = new ModelObjectWithContextMenu.ContextMenu();
         Jenkins.get().clouds.stream().forEach(m::add);
         return m;
     }
 
-    public Cloud getDynamic(String name, StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public Cloud getDynamic(String name, StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         return Jenkins.get().clouds.getByName(name);
     }
 
@@ -186,7 +197,7 @@ public FormValidation doCheckName(@QueryParameter String value) {
      * First check point in creating a new cloud.
      */
     @RequirePOST
-    public synchronized void doCreate(StaplerRequest req, StaplerResponse rsp,
+    public synchronized void doCreate(StaplerRequest2 req, StaplerResponse2 rsp,
                                           @QueryParameter String name, @QueryParameter String mode,
                                           @QueryParameter String from) throws IOException, ServletException, Descriptor.FormException {
         final Jenkins jenkins = Jenkins.get();
@@ -226,7 +237,7 @@ public synchronized void doCreate(StaplerRequest req, StaplerResponse rsp,
         }
     }
 
-    private void handleNewCloudPage(Descriptor<Cloud> descriptor, String name, StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    private void handleNewCloudPage(Descriptor<Cloud> descriptor, String name, StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         checkName(name);
         JSONObject formData = req.getSubmittedForm();
         formData.put("name", name);
@@ -240,7 +251,7 @@ private void handleNewCloudPage(Descriptor<Cloud> descriptor, String name, Stapl
      * Really creates a new agent.
      */
     @POST
-    public synchronized void doDoCreate(StaplerRequest req, StaplerResponse rsp,
+    public synchronized void doDoCreate(StaplerRequest2 req, StaplerResponse2 rsp,
                                             @QueryParameter String cloudDescriptorName) throws IOException, ServletException, Descriptor.FormException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         Descriptor<Cloud> cloudDescriptor = Cloud.all().findByName(cloudDescriptorName);
@@ -256,7 +267,7 @@ public synchronized void doDoCreate(StaplerRequest req, StaplerResponse rsp,
     }
 
     @POST
-    public void doReorder(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doReorder(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         var names = req.getParameterValues("name");
         if (names == null) {
diff --git a/core/src/main/java/jenkins/agents/WebSocketAgents.java b/core/src/main/java/jenkins/agents/WebSocketAgents.java
index d9560f156ebd..1da8d046d56f 100644
--- a/core/src/main/java/jenkins/agents/WebSocketAgents.java
+++ b/core/src/main/java/jenkins/agents/WebSocketAgents.java
@@ -57,8 +57,8 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 @Extension
 @Restricted(NoExternalUse.class)
@@ -71,7 +71,7 @@ public String getUrlName() {
         return WebSockets.isSupported() ? "wsagents" : null;
     }
 
-    public HttpResponse doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public HttpResponse doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         String agent = req.getHeader(JnlpConnectionState.CLIENT_NAME_KEY);
         String secret = req.getHeader(JnlpConnectionState.SECRET_KEY);
         String remoteCapabilityStr = req.getHeader(Capability.KEY);
diff --git a/core/src/main/java/jenkins/appearance/AppearanceGlobalConfiguration.java b/core/src/main/java/jenkins/appearance/AppearanceGlobalConfiguration.java
index 96e61c0c9371..007b9a314dd5 100644
--- a/core/src/main/java/jenkins/appearance/AppearanceGlobalConfiguration.java
+++ b/core/src/main/java/jenkins/appearance/AppearanceGlobalConfiguration.java
@@ -30,18 +30,18 @@
 import hudson.model.Descriptor;
 import hudson.model.ManagementLink;
 import hudson.util.FormApply;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.function.Predicate;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.console.ConsoleUrlProviderGlobalConfiguration;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 @Extension
@@ -94,13 +94,13 @@ public Category getCategory() {
     }
 
     @POST
-    public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    public synchronized void doConfigure(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         boolean result = configure(req, req.getSubmittedForm());
         LOGGER.log(Level.FINE, "appearance saved: " + result);
         FormApply.success(req.getContextPath() + "/manage").generateResponse(req, rsp, null);
     }
 
-    private boolean configure(StaplerRequest req, JSONObject json) throws Descriptor.FormException, IOException {
+    private boolean configure(StaplerRequest2 req, JSONObject json) throws Descriptor.FormException, IOException {
         Jenkins j = Jenkins.get();
         j.checkPermission(Jenkins.MANAGE);
 
@@ -113,7 +113,7 @@ private boolean configure(StaplerRequest req, JSONObject json) throws Descriptor
         return result;
     }
 
-    private boolean configureDescriptor(StaplerRequest req, JSONObject json, Descriptor<?> d) throws Descriptor.FormException {
+    private boolean configureDescriptor(StaplerRequest2 req, JSONObject json, Descriptor<?> d) throws Descriptor.FormException {
         String name = d.getJsonSafeClassName();
         JSONObject js = json.has(name) ? json.getJSONObject(name) : new JSONObject(); // if it doesn't have the property, the method returns invalid null object.
         json.putAll(js);
diff --git a/core/src/main/java/jenkins/console/ConsoleUrlProvider.java b/core/src/main/java/jenkins/console/ConsoleUrlProvider.java
index 0b9e70c3db53..3310f13fd332 100644
--- a/core/src/main/java/jenkins/console/ConsoleUrlProvider.java
+++ b/core/src/main/java/jenkins/console/ConsoleUrlProvider.java
@@ -119,9 +119,9 @@ default Descriptor<ConsoleUrlProvider> getDescriptor() {
             url = run.getUrl() + "console";
         }
         if (url.startsWith("/")) {
-            return Stapler.getCurrentRequest().getContextPath() + url;
+            return Stapler.getCurrentRequest2().getContextPath() + url;
         } else {
-            return Stapler.getCurrentRequest().getContextPath() + '/' + url;
+            return Stapler.getCurrentRequest2().getContextPath() + '/' + url;
         }
     }
 
diff --git a/core/src/main/java/jenkins/console/ConsoleUrlProviderGlobalConfiguration.java b/core/src/main/java/jenkins/console/ConsoleUrlProviderGlobalConfiguration.java
index a63fe679f200..0ce3ca071322 100644
--- a/core/src/main/java/jenkins/console/ConsoleUrlProviderGlobalConfiguration.java
+++ b/core/src/main/java/jenkins/console/ConsoleUrlProviderGlobalConfiguration.java
@@ -43,7 +43,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundSetter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Allows administrators to activate and sort {@link ConsoleUrlProvider} extensions to set defaults for all users.
@@ -79,7 +79,7 @@ public void setProviders(List<ConsoleUrlProvider> providers) {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         // We have to null out providers before data binding to allow all providers to be deleted in the config UI.
         // We use a BulkChange to avoid double saves in other cases.
         try (BulkChange bc = new BulkChange(this)) {
diff --git a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java
index 017fda058051..028528cd523a 100644
--- a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java
+++ b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsAgents.java
@@ -32,8 +32,8 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 @Extension
@@ -58,7 +58,7 @@ public boolean isActivated() {
     }
 
     @RequirePOST
-    public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.hasParameter("no")) {
             disable(true);
             rsp.sendRedirect(req.getContextPath() + "/manage");
diff --git a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java
index d06c3c7bff69..8a73178f3849 100644
--- a/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java
+++ b/core/src/main/java/jenkins/diagnostics/ControllerExecutorsNoAgents.java
@@ -32,8 +32,8 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 @Extension
@@ -52,7 +52,7 @@ public boolean isSecurity() {
     }
 
     @RequirePOST
-    public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.hasParameter("no")) {
             disable(true);
             rsp.sendRedirect(req.getContextPath() + "/manage");
diff --git a/core/src/main/java/jenkins/diagnostics/SecurityIsOffMonitor.java b/core/src/main/java/jenkins/diagnostics/SecurityIsOffMonitor.java
index 4ca6972304b3..04c134333063 100644
--- a/core/src/main/java/jenkins/diagnostics/SecurityIsOffMonitor.java
+++ b/core/src/main/java/jenkins/diagnostics/SecurityIsOffMonitor.java
@@ -5,8 +5,8 @@
 import java.io.IOException;
 import jenkins.model.Jenkins;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -40,7 +40,7 @@ public boolean isSecurity() {
      * Depending on whether the user said "yes" or "no", send him to the right place.
      */
     @RequirePOST
-    public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.hasParameter("no")) {
             disable(true);
             rsp.sendRedirect(req.getContextPath() + "/manage");
diff --git a/core/src/main/java/jenkins/diagnostics/URICheckEncodingMonitor.java b/core/src/main/java/jenkins/diagnostics/URICheckEncodingMonitor.java
index 9fdd7bc38436..df7af46879b0 100644
--- a/core/src/main/java/jenkins/diagnostics/URICheckEncodingMonitor.java
+++ b/core/src/main/java/jenkins/diagnostics/URICheckEncodingMonitor.java
@@ -14,7 +14,7 @@
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @Restricted(NoExternalUse.class)
 @Extension
@@ -36,7 +36,7 @@ public String getDisplayName() {
         return Messages.URICheckEncodingMonitor_DisplayName();
     }
 
-    public FormValidation doCheckURIEncoding(StaplerRequest request) throws IOException {
+    public FormValidation doCheckURIEncoding(StaplerRequest2 request) throws IOException {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
         // expected is non-ASCII String
         final String expected = "\u57f7\u4e8b";
diff --git a/core/src/main/java/jenkins/fingerprints/GlobalFingerprintConfiguration.java b/core/src/main/java/jenkins/fingerprints/GlobalFingerprintConfiguration.java
index 485d0fd2fe55..93f2966c7382 100644
--- a/core/src/main/java/jenkins/fingerprints/GlobalFingerprintConfiguration.java
+++ b/core/src/main/java/jenkins/fingerprints/GlobalFingerprintConfiguration.java
@@ -32,7 +32,7 @@
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundSetter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Allows configuring the settings of fingerprints.
@@ -74,7 +74,7 @@ public void setFingerprintCleanupDisabled(boolean fingerprintCleanupDisabled) {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) {
+    public boolean configure(StaplerRequest2 req, JSONObject json) {
         req.bindJSON(this, json);
         save();
         return true;
diff --git a/core/src/main/java/jenkins/install/SetupWizard.java b/core/src/main/java/jenkins/install/SetupWizard.java
index 4ecd23ef9e81..2707807906f1 100644
--- a/core/src/main/java/jenkins/install/SetupWizard.java
+++ b/core/src/main/java/jenkins/install/SetupWizard.java
@@ -23,6 +23,16 @@
 import hudson.util.HttpResponses;
 import hudson.util.PluginServletFilter;
 import hudson.util.VersionNumber;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpSession;
 import java.io.File;
 import java.io.IOException;
 import java.net.HttpRetryException;
@@ -43,16 +53,6 @@
 import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
 import jenkins.model.Jenkins;
 import jenkins.model.JenkinsLocationConfiguration;
 import jenkins.security.ApiTokenProperty;
@@ -66,10 +66,11 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 import org.kohsuke.stapler.verb.POST;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -332,7 +333,7 @@ public boolean isUsingSecurityToken() {
      */
     @POST
     @Restricted(NoExternalUse.class)
-    public HttpResponse doCreateAdminUser(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public HttpResponse doCreateAdminUser(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         Jenkins j = Jenkins.get();
 
         j.checkPermission(Jenkins.ADMINISTER);
@@ -416,7 +417,7 @@ public HttpResponse doCreateAdminUser(StaplerRequest req, StaplerResponse rsp) t
 
     @POST
     @Restricted(NoExternalUse.class)
-    public HttpResponse doConfigureInstance(StaplerRequest req, @QueryParameter String rootUrl) {
+    public HttpResponse doConfigureInstance(StaplerRequest2 req, @QueryParameter String rootUrl) {
         Jenkins.get().checkPermission(Jenkins.ADMINISTER);
 
         Map<String, String> errors = new HashMap<>();
@@ -756,7 +757,7 @@ public boolean hasSetupWizardFilter() {
     /**
      * This filter will validate that the security token is provided
      */
-    private final Filter FORCE_SETUP_WIZARD_FILTER = new Filter() {
+    private final Filter FORCE_SETUP_WIZARD_FILTER = new CompatibleFilter() {
         @Override
         public void init(FilterConfig cfg) throws ServletException {
         }
diff --git a/core/src/main/java/jenkins/management/AdministrativeMonitorsApi.java b/core/src/main/java/jenkins/management/AdministrativeMonitorsApi.java
index ea2b8e2cf771..8f3f83dd89a9 100644
--- a/core/src/main/java/jenkins/management/AdministrativeMonitorsApi.java
+++ b/core/src/main/java/jenkins/management/AdministrativeMonitorsApi.java
@@ -3,26 +3,26 @@
 import hudson.Extension;
 import hudson.model.PageDecorator;
 import hudson.model.RootAction;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.GET;
 
 @Extension
 @Restricted(NoExternalUse.class)
 public class AdministrativeMonitorsApi implements RootAction {
     @GET
-    public void doNonSecurityPopupContent(StaplerRequest req, StaplerResponse resp) throws IOException, ServletException {
+    public void doNonSecurityPopupContent(StaplerRequest2 req, StaplerResponse2 resp) throws IOException, ServletException {
         AdministrativeMonitorsApiData viewData = new AdministrativeMonitorsApiData(getDecorator().getNonSecurityAdministrativeMonitors());
         req.getView(viewData, "monitorsList.jelly").forward(req, resp);
     }
 
     @GET
-    public void doSecurityPopupContent(StaplerRequest req, StaplerResponse resp) throws IOException, ServletException {
+    public void doSecurityPopupContent(StaplerRequest2 req, StaplerResponse2 resp) throws IOException, ServletException {
         AdministrativeMonitorsApiData viewData = new AdministrativeMonitorsApiData(getDecorator().getSecurityAdministrativeMonitors());
         req.getView(viewData, "monitorsList.jelly").forward(req, resp);
     }
diff --git a/core/src/main/java/jenkins/management/AdministrativeMonitorsConfiguration.java b/core/src/main/java/jenkins/management/AdministrativeMonitorsConfiguration.java
index 78de6ccfc387..cc4ea526566f 100644
--- a/core/src/main/java/jenkins/management/AdministrativeMonitorsConfiguration.java
+++ b/core/src/main/java/jenkins/management/AdministrativeMonitorsConfiguration.java
@@ -34,13 +34,13 @@
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @Extension
 @Restricted(NoExternalUse.class)
 public class AdministrativeMonitorsConfiguration extends GlobalConfiguration {
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         JSONArray monitors = json.optJSONArray("administrativeMonitor");
         for (AdministrativeMonitor am : AdministrativeMonitor.all()) {
             try {
diff --git a/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java b/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java
index 5b94090f4e3b..d531f898c065 100644
--- a/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java
+++ b/core/src/main/java/jenkins/management/AdministrativeMonitorsDecorator.java
@@ -43,7 +43,7 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Ancestor;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Show notifications and popups for active administrative monitors on all pages.
@@ -143,7 +143,7 @@ public Collection<AdministrativeMonitor> getMonitorsToDisplay() {
             return null;
         }
 
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
 
         if (req == null) {
             return null;
diff --git a/core/src/main/java/jenkins/management/ShutdownLink.java b/core/src/main/java/jenkins/management/ShutdownLink.java
index a5ebcba4f8d3..7f8b4cd36495 100644
--- a/core/src/main/java/jenkins/management/ShutdownLink.java
+++ b/core/src/main/java/jenkins/management/ShutdownLink.java
@@ -28,15 +28,15 @@
 import hudson.Extension;
 import hudson.model.ManagementLink;
 import hudson.security.Permission;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 @Extension(ordinal = Integer.MIN_VALUE)
@@ -66,7 +66,7 @@ public String getUrlName() {
     }
 
     @POST
-    public synchronized void doPrepare(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, InterruptedException {
+    public synchronized void doPrepare(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, InterruptedException {
         Jenkins.get().checkPermission(Jenkins.MANAGE);
 
         JSONObject submittedForm = req.getSubmittedForm();
@@ -77,7 +77,7 @@ public synchronized void doPrepare(StaplerRequest req, StaplerResponse rsp) thro
     }
 
     @POST
-    public synchronized void doCancel(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doCancel(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         Jenkins.get().checkPermission(Jenkins.MANAGE);
 
         LOGGER.log(Level.FINE, "Shutdown cancel requested by user {0}", Jenkins.getAuthentication().getName());
diff --git a/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java b/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java
index 9fe7412699f4..d6dfeafd68f4 100644
--- a/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java
+++ b/core/src/main/java/jenkins/model/ArtifactManagerConfiguration.java
@@ -31,7 +31,7 @@
 import java.io.IOException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * List of configured {@link ArtifactManagerFactory}s.
@@ -55,7 +55,7 @@ public DescribableList<ArtifactManagerFactory, ArtifactManagerFactoryDescriptor>
         return artifactManagerFactories;
     }
 
-    @Override public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    @Override public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             artifactManagerFactories.rebuildHetero(req, json, ArtifactManagerFactoryDescriptor.all(), "artifactManagerFactories");
             return true;
diff --git a/core/src/main/java/jenkins/model/AssetManager.java b/core/src/main/java/jenkins/model/AssetManager.java
index 5da61d203026..65882afc64d5 100644
--- a/core/src/main/java/jenkins/model/AssetManager.java
+++ b/core/src/main/java/jenkins/model/AssetManager.java
@@ -4,16 +4,16 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Extension;
 import hudson.model.UnprotectedRootAction;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Enumeration;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.ClassLoaderReflectionToolkit;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Serves files located in the {@code /assets} classpath directory via the Jenkins core ClassLoader.
@@ -46,7 +46,7 @@ public String getUrlName() {
     /**
      * Exposes assets in the core classloader over HTTP.
      */
-    public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String path = req.getRestOfPath();
         URL resource = findResource(path);
 
diff --git a/core/src/main/java/jenkins/model/BuiltInNodeMigration.java b/core/src/main/java/jenkins/model/BuiltInNodeMigration.java
index 7f08aa7d5b40..c777407f3c65 100644
--- a/core/src/main/java/jenkins/model/BuiltInNodeMigration.java
+++ b/core/src/main/java/jenkins/model/BuiltInNodeMigration.java
@@ -26,14 +26,14 @@
 
 import hudson.Extension;
 import hudson.model.AdministrativeMonitor;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -51,7 +51,7 @@ public boolean isActivated() {
     }
 
     @RequirePOST
-    public void doAct(StaplerRequest req, StaplerResponse rsp, @QueryParameter String yes, @QueryParameter String no) throws IOException, ServletException {
+    public void doAct(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter String yes, @QueryParameter String no) throws IOException, ServletException {
         if (yes != null) {
             Jenkins.get().performRenameMigration();
         } else if (no != null) {
diff --git a/core/src/main/java/jenkins/model/GlobalBuildDiscarderConfiguration.java b/core/src/main/java/jenkins/model/GlobalBuildDiscarderConfiguration.java
index 023eb52a4ff6..869ec901757b 100644
--- a/core/src/main/java/jenkins/model/GlobalBuildDiscarderConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalBuildDiscarderConfiguration.java
@@ -33,7 +33,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Global configuration UI for background build discarders
@@ -65,7 +65,7 @@ public DescribableList<GlobalBuildDiscarderStrategy, GlobalBuildDiscarderStrateg
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             configuredBuildDiscarders.rebuildHetero(req, json, GlobalBuildDiscarderStrategyDescriptor.all(), "configuredBuildDiscarders");
             return true;
diff --git a/core/src/main/java/jenkins/model/GlobalConfiguration.java b/core/src/main/java/jenkins/model/GlobalConfiguration.java
index 4a5aa76ba117..af788945b2a2 100644
--- a/core/src/main/java/jenkins/model/GlobalConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalConfiguration.java
@@ -3,10 +3,12 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.ExtensionList;
 import hudson.ExtensionPoint;
+import hudson.Util;
 import hudson.model.Describable;
 import hudson.model.Descriptor;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Convenient base class for extensions that contributes to the system configuration page but nothing
@@ -28,7 +30,7 @@
  *
  * <p>
  * While an implementation might store its actual configuration data in various ways,
- * meaning {@link #configure(StaplerRequest, JSONObject)} must be overridden,
+ * meaning {@link #configure(StaplerRequest2, JSONObject)} must be overridden,
  * in the normal case you would simply define persistable fields with getters and setters.
  * The {@code config} view would use data-bound controls like {@code f:entry}.
  * Then make sure your constructor calls {@link #load} and your setters call {@link #save}.
@@ -58,12 +60,29 @@ public String getGlobalConfigPage() {
     }
 
     /**
-     * By default, calls {@link StaplerRequest#bindJSON(Object, JSONObject)},
+     * By default, calls {@link StaplerRequest2#bindJSON(Object, JSONObject)},
      * appropriate when your implementation has getters and setters for all fields.
      * <p>{@inheritDoc}
      */
     @Override
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
+        if (Util.isOverridden(GlobalConfiguration.class, getClass(), "configure", StaplerRequest.class, JSONObject.class)) {
+            return configure(StaplerRequest.fromStaplerRequest2(req), json);
+        } else {
+            return configureImpl(req, json);
+        }
+    }
+
+    /**
+     * @deprecated use {@link #configure(StaplerRequest2, JSONObject)}
+     */
+    @Deprecated
+    @Override
     public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+        return configureImpl(StaplerRequest.toStaplerRequest2(req), json);
+    }
+
+    private boolean configureImpl(StaplerRequest2 req, JSONObject json) throws FormException {
         req.bindJSON(this, json);
         return true;
     }
diff --git a/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java b/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java
index b40b261f0f31..2ca6863c014b 100644
--- a/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalNodePropertiesConfiguration.java
@@ -6,7 +6,7 @@
 import java.io.IOException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Include {@link NodePropertyDescriptor} configurations.
@@ -16,7 +16,7 @@
 @Extension(ordinal = 110) @Symbol("nodeProperties") // historically this was placed above GlobalPluginConfiguration
 public class GlobalNodePropertiesConfiguration extends GlobalConfiguration {
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             Jenkins j = Jenkins.get();
             JSONObject np = json.getJSONObject("globalNodeProperties");
diff --git a/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java b/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java
index e2803a9c1e76..d7b2336f57c0 100644
--- a/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalPluginConfiguration.java
@@ -4,11 +4,11 @@
 import hudson.Plugin;
 import hudson.PluginWrapper;
 import hudson.StructuredForm;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Include config.jelly defined for {@link Plugin}s.
@@ -21,7 +21,7 @@
 @Extension(ordinal = 100) @Symbol("plugin") // historically this was placed above general configuration from arbitrary descriptors
 public class GlobalPluginConfiguration  extends GlobalConfiguration {
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             for (JSONObject o : StructuredForm.toList(json, "plugin")) {
                 String pluginName = o.getString("name");
diff --git a/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java b/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java
index a1ed1ebd763a..35c3cc3193fd 100644
--- a/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalProjectNamingStrategyConfiguration.java
@@ -29,7 +29,7 @@
 import hudson.security.Permission;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Configures the project naming strategy.
@@ -40,7 +40,7 @@
 public class GlobalProjectNamingStrategyConfiguration extends GlobalConfiguration {
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws hudson.model.Descriptor.FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws hudson.model.Descriptor.FormException {
         // for compatibility reasons, the actual value is stored in Jenkins
         Jenkins j = Jenkins.get();
         final JSONObject optJSONObject = json.optJSONObject("useProjectNamingStrategy");
diff --git a/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java b/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java
index e3cbf464acbc..91ccba1c268e 100644
--- a/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalQuietPeriodConfiguration.java
@@ -30,7 +30,7 @@
 import java.io.IOException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Configures the system-default quiet period.
@@ -44,7 +44,7 @@ public int getQuietPeriod() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         int i = 0;
         try {
             i = Integer.parseInt(json.getString("quietPeriod"));
diff --git a/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java b/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java
index c2543a24d4b7..e60ac1c9a598 100644
--- a/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java
+++ b/core/src/main/java/jenkins/model/GlobalSCMRetryCountConfiguration.java
@@ -31,7 +31,7 @@
 import net.sf.json.JSONException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Configures global SCM retry count default.
@@ -45,7 +45,7 @@ public int getScmCheckoutRetryCount() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             // for compatibility reasons, this value is stored in Jenkins
             Jenkins.get().setScmCheckoutRetryCount(json.getInt("scmCheckoutRetryCount"));
diff --git a/core/src/main/java/jenkins/model/Jenkins.java b/core/src/main/java/jenkins/model/Jenkins.java
index a648935527ae..6b3500e6b66a 100644
--- a/core/src/main/java/jenkins/model/Jenkins.java
+++ b/core/src/main/java/jenkins/model/Jenkins.java
@@ -35,12 +35,12 @@
 import static hudson.init.InitMilestone.JOB_LOADED;
 import static hudson.init.InitMilestone.PLUGINS_PREPARED;
 import static hudson.init.InitMilestone.SYSTEM_CONFIG_LOADED;
+import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
+import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 import static java.util.logging.Level.FINE;
 import static java.util.logging.Level.INFO;
 import static java.util.logging.Level.SEVERE;
 import static java.util.logging.Level.WARNING;
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-import static javax.servlet.http.HttpServletResponse.SC_NOT_FOUND;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.inject.Inject;
@@ -210,6 +210,14 @@
 import hudson.views.MyViewsTabBar;
 import hudson.views.ViewsTabBar;
 import hudson.widgets.Widget;
+import io.jenkins.servlet.RequestDispatcherWrapper;
+import io.jenkins.servlet.ServletContextWrapper;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
@@ -257,11 +265,6 @@
 import java.util.logging.Logger;
 import java.util.stream.Collectors;
 import javax.crypto.SecretKey;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.AgentProtocol;
 import jenkins.ErrorAttributeFilter;
 import jenkins.ExtensionComponentSet;
@@ -283,6 +286,7 @@
 import jenkins.security.stapler.StaplerDispatchValidator;
 import jenkins.security.stapler.StaplerDispatchable;
 import jenkins.security.stapler.StaplerFilteredActionListener;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.security.stapler.TypedFilter;
 import jenkins.slaves.WorkspaceLocator;
 import jenkins.util.JenkinsJVM;
@@ -320,7 +324,9 @@
 import org.kohsuke.stapler.StaplerFallback;
 import org.kohsuke.stapler.StaplerProxy;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.export.Exported;
@@ -744,8 +750,20 @@ private static int getSlaveAgentPortInitialValue(int def) {
     @Deprecated
     public final transient NodeProvisioner overallNodeProvisioner = unlabeledNodeProvisioner;
 
+    /**
+     * @deprecated use {@link #getServletContext}
+     */
+    @Deprecated
+    public final transient javax.servlet.ServletContext servletContext;
+
+    private final transient ServletContext jakartaServletContext;
 
-    public final transient ServletContext servletContext;
+    /**
+     * @since TODO
+     */
+    public ServletContext getServletContext() {
+        return this.jakartaServletContext;
+    }
 
     /**
      * Transient action list. Useful for adding navigation items to the navigation bar
@@ -922,7 +940,8 @@ protected Jenkins(File root, ServletContext context, PluginManager pluginManager
         // As Jenkins is starting, grant this process full control
         try (ACLContext ctx = ACL.as2(ACL.SYSTEM2)) {
             this.root = root;
-            this.servletContext = context;
+            this.jakartaServletContext = context;
+            this.servletContext = ServletContextWrapper.fromJakartServletContext(context);
             computeVersion(context);
             if (theInstance != null)
                 throw new IllegalStateException("second instance");
@@ -972,7 +991,7 @@ protected Jenkins(File root, ServletContext context, PluginManager pluginManager
             if (pluginManager == null)
                 pluginManager = PluginManager.createDefault(this);
             this.pluginManager = pluginManager;
-            WebApp webApp = WebApp.get(servletContext);
+            WebApp webApp = WebApp.get(getServletContext());
             // JSON binding needs to be able to see all the classes from all the plugins
             webApp.setClassLoader(pluginManager.uberClassLoader);
             webApp.setJsonInErrorMessageSanitizer(RedactSecretJsonInErrorMessageSanitizer.INSTANCE);
@@ -990,7 +1009,7 @@ protected Jenkins(File root, ServletContext context, PluginManager pluginManager
             webApp.setDispatchValidator(new StaplerDispatchValidator());
             webApp.setFilteredDispatchTriggerListener(actionListener);
 
-            adjuncts = new AdjunctManager(servletContext, pluginManager.uberClassLoader, "adjuncts/" + SESSION_HASH, TimeUnit.DAYS.toMillis(365));
+            adjuncts = new AdjunctManager(getServletContext(), pluginManager.uberClassLoader, "adjuncts/" + SESSION_HASH, TimeUnit.DAYS.toMillis(365));
 
             ClassFilterImpl.register();
 
@@ -1391,7 +1410,7 @@ public int getExpectedPort() {
         }
 
         @RequirePOST
-        public void doAct(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doAct(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             j.forceSetSlaveAgentPort(getExpectedPort());
             rsp.sendRedirect2(req.getContextPath() + "/manage");
         }
@@ -1458,9 +1477,9 @@ public void setNoUsageStatistics(Boolean noUsageStatistics) throws IOException {
 
     public Api getApi() {
         /* Do not show "REST API" link in footer when on 404 error page */
-        final StaplerRequest req = Stapler.getCurrentRequest();
+        final StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req != null) {
-            final Object attribute = req.getAttribute("javax.servlet.error.message");
+            final Object attribute = req.getAttribute("jakarta.servlet.error.message");
             if (attribute != null) {
                 return null;
             }
@@ -2506,7 +2525,7 @@ public String getUrlChildPrefix() {
         if (url != null) {
             return Util.ensureEndsWith(url, "/");
         }
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req != null)
             return getRootUrlFromRequest();
         return null;
@@ -2524,7 +2543,7 @@ public String getConfiguredRootUrl() {
     /**
      * Is Jenkins running in HTTPS?
      *
-     * Note that we can't really trust {@link StaplerRequest#isSecure()} because HTTPS might be terminated
+     * Note that we can't really trust {@link StaplerRequest2#isSecure()} because HTTPS might be terminated
      * in the reverse proxy.
      */
     public boolean isRootUrlSecure() {
@@ -2550,7 +2569,7 @@ public boolean isRootUrlSecure() {
      * @since 1.263
      */
     public @NonNull String getRootUrlFromRequest() {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req == null) {
             throw new IllegalStateException("cannot call getRootUrlFromRequest from outside a request handling thread");
         }
@@ -2604,7 +2623,7 @@ public boolean isRootUrlSecure() {
      * @param defaultValue the value to return if the header is absent.
      * @return the originating entry of the header or the default value if the header was not present.
      */
-    private static String getXForwardedHeader(StaplerRequest req, String header, String defaultValue) {
+    private static String getXForwardedHeader(StaplerRequest2 req, String header, String defaultValue) {
         String value = req.getHeader(header);
         if (value != null) {
             int index = value.indexOf(',');
@@ -2791,7 +2810,7 @@ public void setSecurityRealm(@CheckForNull SecurityRealm securityRealm) {
      */
     private void resetFilter(@CheckForNull SecurityRealm securityRealm, @CheckForNull IdStrategy oldUserIdStrategy) {
         try {
-            HudsonFilter filter = HudsonFilter.get(servletContext);
+            HudsonFilter filter = HudsonFilter.get(getServletContext());
             if (filter == null) {
                 // Fix for JENKINS-3069: This filter is not necessarily initialized before the servlets.
                 // when HudsonFilter does come back, it'll initialize itself.
@@ -3263,7 +3282,7 @@ public void onRenamed(TopLevelItem job, String oldName, String newName) throws I
     }
 
     /**
-     * Called in response to {@link Job#doDoDelete(StaplerRequest, StaplerResponse)}
+     * Called in response to {@link Job#doDoDelete(StaplerRequest2, StaplerResponse2)}
      */
     @Override
     public void onDeleted(TopLevelItem item) throws IOException {
@@ -4064,7 +4083,7 @@ public Object getDynamic(String token) {
      * Accepts submission from the configuration page.
      */
     @POST
-    public synchronized void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public synchronized void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         try (BulkChange bc = new BulkChange(this)) {
             checkPermission(MANAGE);
 
@@ -4101,11 +4120,11 @@ public void setCrumbIssuer(CrumbIssuer issuer) {
         crumbIssuer = issuer;
     }
 
-    public synchronized void doTestPost(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doTestPost(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.sendRedirect("foo");
     }
 
-    private boolean configureDescriptor(StaplerRequest req, JSONObject json, Descriptor<?> d) throws FormException {
+    private boolean configureDescriptor(StaplerRequest2 req, JSONObject json, Descriptor<?> d) throws FormException {
         // collapse the structure to remain backward compatible with the JSON structure before 1.
         String name = d.getJsonSafeClassName();
         JSONObject js = json.has(name) ? json.getJSONObject(name) : new JSONObject(); // if it doesn't have the property, the method returns invalid null object.
@@ -4117,7 +4136,7 @@ private boolean configureDescriptor(StaplerRequest req, JSONObject json, Descrip
      * Accepts submission from the node configuration page.
      */
     @POST
-    public synchronized void doConfigExecutorsSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public synchronized void doConfigExecutorsSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         checkPermission(ADMINISTER);
 
         try (BulkChange bc = new BulkChange(this)) {
@@ -4139,7 +4158,7 @@ public synchronized void doConfigExecutorsSubmit(StaplerRequest req, StaplerResp
      * Accepts the new description.
      */
     @RequirePOST
-    public synchronized void doSubmitDescription(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized void doSubmitDescription(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         getPrimaryView().doSubmitDescription(req, rsp);
     }
 
@@ -4227,7 +4246,7 @@ public synchronized HttpRedirect doCancelQuietDown() {
     }
 
     public HttpResponse doToggleCollapse() throws ServletException, IOException {
-        final StaplerRequest request = Stapler.getCurrentRequest();
+        final StaplerRequest2 request = Stapler.getCurrentRequest2();
         final String paneId = request.getParameter("paneId");
 
         PaneStatusProperties.forCurrentUser().toggleCollapsed(paneId);
@@ -4239,7 +4258,7 @@ public HttpResponse doToggleCollapse() throws ServletException, IOException {
      * Backward compatibility. Redirect to the thread dump.
      */
     // TODO annotate @GET once baseline includes Stapler version XXX
-    public void doClassicThreadDump(StaplerResponse rsp) throws IOException, ServletException {
+    public void doClassicThreadDump(StaplerResponse2 rsp) throws IOException, ServletException {
         rsp.sendRedirect2("threadDump");
     }
 
@@ -4283,7 +4302,7 @@ public Map<String, Map<String, String>> getAllThreadDumps() throws IOException,
 
     @Override
     @RequirePOST
-    public synchronized TopLevelItem doCreateItem(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public synchronized TopLevelItem doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         return itemGroupMixIn.createTopLevelItem(req, rsp);
     }
 
@@ -4308,7 +4327,7 @@ public <T extends TopLevelItem> T copy(T src, String name) throws IOException {
     }
 
     @POST
-    public synchronized void doCreateView(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+    public synchronized void doCreateView(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
         checkPermission(View.CREATE);
         addView(View.create(req, rsp, this));
     }
@@ -4364,7 +4383,7 @@ private static String toPrintableName(String name) {
      *
      * @see BasicAuthenticationFilter
      */
-    public void doSecured(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doSecured(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         // TODO fire something in SecurityListener? (seems to be used only for REST calls when LegacySecurityRealm is active)
 
         if (req.getUserPrincipal() == null) {
@@ -4386,7 +4405,7 @@ public void doSecured(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
      * Called once the user logs in. Just forward to the top page.
      * Used only by {@link LegacySecurityRealm}.
      */
-    public void doLoginEntry(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doLoginEntry(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (req.getUserPrincipal() == null) {
             rsp.sendRedirect2("noPrincipal");
             return;
@@ -4415,13 +4434,28 @@ public void doLoginEntry(StaplerRequest req, StaplerResponse rsp) throws IOExcep
 
     /**
      * Logs out the user.
+     *
+     * @since TODO
      */
-    public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doLogout(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String user = getAuthentication2().getName();
         securityRealm.doLogout(req, rsp);
         SecurityListener.fireLoggedOut(user);
     }
 
+    /**
+     * @deprecated use {@link #doLogout(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            doLogout(req != null ? StaplerRequest.toStaplerRequest2(req) : null, rsp != null ? StaplerResponse.toStaplerResponse2(rsp) : null);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Serves jar files for inbound agents.
      */
@@ -4429,7 +4463,7 @@ public Slave.JnlpJar getJnlpJars(String fileName) {
         return new Slave.JnlpJar(fileName);
     }
 
-    public Slave.JnlpJar doJnlpJars(StaplerRequest req) {
+    public Slave.JnlpJar doJnlpJars(StaplerRequest2 req) {
         return new Slave.JnlpJar(req.getRestOfPath().substring(1));
     }
 
@@ -4442,7 +4476,7 @@ public synchronized HttpResponse doReload() throws IOException {
         getLifecycle().onReload(getAuthentication2().getName(), null);
 
         // engage "loading ..." UI and then run the actual task in a separate thread
-        WebApp.get(servletContext).setApp(new HudsonIsLoading());
+        WebApp.get(getServletContext()).setApp(new HudsonIsLoading());
 
         new Thread("Jenkins config reload thread") {
             @Override
@@ -4452,7 +4486,7 @@ public void run() {
                     getLifecycle().onReady();
                 } catch (Exception e) {
                     LOGGER.log(SEVERE, "Failed to reload Jenkins config", e);
-                    new JenkinsReloadFailed(e).publish(servletContext, root);
+                    new JenkinsReloadFailed(e).publish(getServletContext(), root);
                 }
             }
         }.start();
@@ -4481,14 +4515,14 @@ public void reload() throws IOException, InterruptedException, ReactorException
 
         User.reload();
         queue.load();
-        WebApp.get(servletContext).setApp(this);
+        WebApp.get(getServletContext()).setApp(this);
     }
 
     /**
      * Do a finger-print check.
      */
     @RequirePOST
-    public void doDoFingerprintCheck(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doDoFingerprintCheck(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         // Parse the request
         try (MultipartFormDataParser p = new MultipartFormDataParser(req, 10)) {
             if (isUseCrumbs() && !getCrumbIssuer().validateCrumb(req, p)) {
@@ -4505,7 +4539,7 @@ public void doDoFingerprintCheck(StaplerRequest req, StaplerResponse rsp) throws
      */
     @RequirePOST
     @SuppressFBWarnings(value = "DM_GC", justification = "for debugging")
-    public void doGc(StaplerResponse rsp) throws IOException {
+    public void doGc(StaplerResponse2 rsp) throws IOException {
         checkPermission(Jenkins.ADMINISTER);
         System.gc();
         rsp.setStatus(HttpServletResponse.SC_OK);
@@ -4523,7 +4557,7 @@ public void doException() {
     }
 
     @Override
-    public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws IOException, JellyException {
+    public ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws IOException, JellyException {
         ContextMenu menu = new ContextMenu().from(this, request, response);
         for (MenuItem i : menu.items) {
             if (i.url.equals(request.getContextPath() + "/manage")) {
@@ -4535,7 +4569,7 @@ public ContextMenu doContextMenu(StaplerRequest request, StaplerResponse respons
     }
 
     @Override
-    public ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+    public ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
         ContextMenu menu = new ContextMenu();
         for (View view : getViews()) {
             menu.add(view.getViewUrl(), view.getDisplayName());
@@ -4579,7 +4613,7 @@ public DirectoryBrowserSupport doUserContent() {
      * This first replaces "app" to {@link HudsonIsRestarting}
      */
     @CLIMethod(name = "restart")
-    public void doRestart(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, RestartNotSupportedException {
+    public void doRestart(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, RestartNotSupportedException {
         checkPermission(MANAGE);
         if (req != null && req.getMethod().equals("GET")) {
             req.getView(this, "_restart.jelly").forward(req, rsp);
@@ -4600,7 +4634,7 @@ public void doRestart(StaplerRequest req, StaplerResponse rsp) throws IOExceptio
      */
     @WebMethod(name = "404")
     @Restricted(NoExternalUse.class)
-    public void generateNotFoundResponse(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+    public void generateNotFoundResponse(StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
         if (ResourceDomainConfiguration.isResourceRequest(req)) {
             rsp.forward(this, "_404_simple", req);
         } else {
@@ -4620,12 +4654,12 @@ public void generateNotFoundResponse(StaplerRequest req, StaplerResponse rsp) th
      * Builds that cannot continue while the controller is not running have to finish or pause before it can proceed.
      * No new builds will be started. No new jobs are accepted.
      *
-     * @deprecated use {@link #doSafeRestart(StaplerRequest, String)} instead.
+     * @deprecated use {@link #doSafeRestart(StaplerRequest2, String)} instead.
      *
      */
     @Deprecated(since = "2.414")
     public HttpResponse doSafeRestart(StaplerRequest req) throws IOException, ServletException, RestartNotSupportedException {
-        return doSafeRestart(req, null);
+        return doSafeRestart(StaplerRequest.toStaplerRequest2(req), null);
     }
 
     /**
@@ -4633,7 +4667,7 @@ public HttpResponse doSafeRestart(StaplerRequest req) throws IOException, Servle
      *
      * @since 2.414
      */
-    public HttpResponse doSafeRestart(StaplerRequest req, @QueryParameter("message") String message) throws IOException, ServletException, RestartNotSupportedException {
+    public HttpResponse doSafeRestart(StaplerRequest2 req, @QueryParameter("message") String message) throws IOException, ServletException, RestartNotSupportedException {
         checkPermission(MANAGE);
         if (req != null && req.getMethod().equals("GET")) {
             return HttpResponses.forwardToView(this, "_safeRestart.jelly");
@@ -4664,7 +4698,7 @@ private static Lifecycle restartableLifecycle() throws RestartNotSupportedExcept
      */
     public void restart() throws RestartNotSupportedException {
         final Lifecycle lifecycle = restartableLifecycle();
-        servletContext.setAttribute("app", new HudsonIsRestarting());
+        getServletContext().setAttribute("app", new HudsonIsRestarting());
 
         new Thread("restart thread") {
             final String exitUser = getAuthentication2().getName();
@@ -4717,7 +4751,7 @@ public void run() {
                     doQuietDown(true, 0, message, true);
                     // Make sure isQuietingDown is still true.
                     if (isQuietingDown()) {
-                        servletContext.setAttribute("app", new HudsonIsRestarting(true));
+                        getServletContext().setAttribute("app", new HudsonIsRestarting(true));
                         // give some time for the browser to load the "reloading" page
                         lifecycle.onStatusUpdate("Restart in 10 seconds");
                         Thread.sleep(TimeUnit.SECONDS.toMillis(10));
@@ -4763,7 +4797,7 @@ protected RestartCause() {
      */
     @CLIMethod(name = "shutdown")
     @RequirePOST
-    public void doExit(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doExit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         checkPermission(ADMINISTER);
         final String exitUser = getAuthentication2().getName();
         final String exitAddr = req != null ? req.getRemoteAddr() : null;
@@ -4797,7 +4831,7 @@ public void run() {
      */
     @CLIMethod(name = "safe-shutdown")
     @RequirePOST
-    public HttpResponse doSafeExit(StaplerRequest req) throws IOException {
+    public HttpResponse doSafeExit(StaplerRequest2 req) throws IOException {
         checkPermission(ADMINISTER);
         quietDownInfo = new QuietDownInfo();
         final String exitUser = getAuthentication2().getName();
@@ -4824,6 +4858,15 @@ public void run() {
         return HttpResponses.plainText("Shutting down as soon as all jobs are complete");
     }
 
+    /**
+     * @deprecated use {@link #doSafeExit(StaplerRequest2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public HttpResponse doSafeExit(StaplerRequest req) throws IOException {
+        return doSafeExit(req != null ? StaplerRequest.toStaplerRequest2(req) : null);
+    }
+
     /**
      * Gets the {@link Authentication} object that represents the user
      * associated with the current request.
@@ -4852,21 +4895,47 @@ public void run() {
      * For system diagnostics.
      * Run arbitrary Groovy script.
      */
-    public void doScript(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScript(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         _doScript(req, rsp, req.getView(this, "_script.jelly"), FilePath.localChannel, getACL());
     }
 
+    /**
+     * @deprecated use {@link #doScript(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doScript(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            _doScript(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), StaplerRequest.toStaplerRequest2(req).getView(this, "_script.jelly"), FilePath.localChannel, getACL());
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Run arbitrary Groovy script and return result as plain text.
      */
-    public void doScriptText(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doScriptText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         _doScript(req, rsp, req.getView(this, "_scriptText.jelly"), FilePath.localChannel, getACL());
     }
 
     /**
-     * @since 1.509.1
+     * @deprecated use {@link #doScriptText(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    public void doScriptText(StaplerRequest req, StaplerResponse rsp) throws IOException, javax.servlet.ServletException {
+        try {
+            _doScript(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), StaplerRequest.toStaplerRequest2(req).getView(this, "_scriptText.jelly"), FilePath.localChannel, getACL());
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
+    /**
+     * @since TODO
      */
-    public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDispatcher view, VirtualChannel channel, ACL acl) throws IOException, ServletException {
+    public static void _doScript(StaplerRequest2 req, StaplerResponse2 rsp, RequestDispatcher view, VirtualChannel channel, ACL acl) throws IOException, ServletException {
         // ability to run arbitrary script is dangerous
         acl.checkPermission(ADMINISTER);
 
@@ -4892,13 +4961,26 @@ public static void _doScript(StaplerRequest req, StaplerResponse rsp, RequestDis
         view.forward(req, rsp);
     }
 
+    /**
+     * @deprecated use {@link #_doScript(StaplerRequest2, StaplerResponse2, RequestDispatcher, VirtualChannel, ACL)}
+     * @since 1.509.1
+     */
+    @Deprecated
+    public static void _doScript(StaplerRequest req, StaplerResponse rsp, javax.servlet.RequestDispatcher view, VirtualChannel channel, ACL acl) throws IOException, javax.servlet.ServletException {
+        try {
+            _doScript(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), RequestDispatcherWrapper.toJakartaRequestDispatcher(view), channel, acl);
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Evaluates the Jelly script submitted by the client.
      *
      * This is useful for system administration as well as unit testing.
      */
     @RequirePOST
-    public void doEval(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doEval(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         checkPermission(ADMINISTER);
         req.getWebApp().getDispatchValidator().allowDispatch(req, rsp);
         try {
@@ -4913,7 +4995,7 @@ public void doEval(StaplerRequest req, StaplerResponse rsp) throws IOException,
     /**
      * Sign up for the user account.
      */
-    public void doSignup(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doSignup(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         if (getSecurityRealm().allowsSignup()) {
             req.getView(getSecurityRealm(), "signup.jelly").forward(req, rsp);
             return;
@@ -4924,7 +5006,7 @@ public void doSignup(StaplerRequest req, StaplerResponse rsp) throws IOException
     /**
      * Changes the icon size by changing the cookie
      */
-    public void doIconSize(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doIconSize(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String qs = req.getQueryString();
         if (qs == null)
             throw new ServletException();
@@ -4939,7 +5021,7 @@ public void doIconSize(StaplerRequest req, StaplerResponse rsp) throws IOExcepti
     }
 
     @RequirePOST
-    public void doFingerprintCleanup(StaplerResponse rsp) throws IOException {
+    public void doFingerprintCleanup(StaplerResponse2 rsp) throws IOException {
         checkPermission(ADMINISTER);
         FingerprintCleanupThread.invoke();
         rsp.setStatus(HttpServletResponse.SC_OK);
@@ -4948,7 +5030,7 @@ public void doFingerprintCleanup(StaplerResponse rsp) throws IOException {
     }
 
     @RequirePOST
-    public void doWorkspaceCleanup(StaplerResponse rsp) throws IOException {
+    public void doWorkspaceCleanup(StaplerResponse2 rsp) throws IOException {
         checkPermission(ADMINISTER);
         WorkspaceCleanupThread.invoke();
         rsp.setStatus(HttpServletResponse.SC_OK);
@@ -4959,7 +5041,7 @@ public void doWorkspaceCleanup(StaplerResponse rsp) throws IOException {
     /**
      * If the user chose the default JDK, make sure we got 'java' in PATH.
      */
-    public FormValidation doDefaultJDKCheck(StaplerRequest request, @QueryParameter String value) {
+    public FormValidation doDefaultJDKCheck(StaplerRequest2 request, @QueryParameter String value) {
         if (!JDK.isDefaultName(value))
             // assume the user configured named ones properly in system config ---
             // or else system config should have reported form field validation errors.
@@ -5022,7 +5104,7 @@ public FormValidation doViewExistsCheck(@QueryParameter String value) {
      * strategy here, though the current implementation is based on
      * file extensions.
      */
-    public void doResources(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public void doResources(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         String path = req.getRestOfPath();
         // cut off the "..." portion of /resources/.../path/to/file
         // as this is only used to make path unique (which in turn
@@ -5043,7 +5125,7 @@ public void doResources(StaplerRequest req, StaplerResponse rsp) throws IOExcept
     }
 
     /**
-     * Extension list that {@link #doResources(StaplerRequest, StaplerResponse)} can serve.
+     * Extension list that {@link #doResources(StaplerRequest2, StaplerResponse2)} can serve.
      * This set is mutable to allow plugins to add additional extensions.
      */
     @SuppressFBWarnings(value = "MS_MUTABLE_COLLECTION_PKGPROTECT", justification = "mutable to allow plugins to add additional extensions")
@@ -5054,12 +5136,12 @@ public void doResources(StaplerRequest req, StaplerResponse rsp) throws IOExcept
     /**
      * Checks if container uses UTF-8 to decode URLs. See
      * http://wiki.jenkins-ci.org/display/JENKINS/Tomcat#Tomcat-i18n
-     * @deprecated use {@link URICheckEncodingMonitor#doCheckURIEncoding(StaplerRequest)}
+     * @deprecated use {@link URICheckEncodingMonitor#doCheckURIEncoding(StaplerRequest2)}
      */
     @Restricted(NoExternalUse.class)
     @RestrictedSince("2.37")
     @Deprecated
-    public FormValidation doCheckURIEncoding(StaplerRequest request) throws IOException {
+    public FormValidation doCheckURIEncoding(StaplerRequest2 request) throws IOException {
         return ExtensionList.lookupSingleton(URICheckEncodingMonitor.class).doCheckURIEncoding(request);
     }
 
@@ -5214,7 +5296,7 @@ public Object getTarget() {
         try {
             checkPermission(READ);
         } catch (AccessDeniedException e) {
-            if (!isSubjectToMandatoryReadPermissionCheck(Stapler.getCurrentRequest().getRestOfPath())) {
+            if (!isSubjectToMandatoryReadPermissionCheck(Stapler.getCurrentRequest2().getRestOfPath())) {
                 return this;
             }
 
@@ -5244,7 +5326,7 @@ public boolean isSubjectToMandatoryReadPermissionCheck(String restOfPath) {
 
         // TODO SlaveComputer.doSlaveAgentJnlp; there should be an annotation to request unprotected access
         if ((isAgentJnlpPath(restOfPath, "jenkins") || isAgentJnlpPath(restOfPath, "slave"))
-            && "true".equals(Stapler.getCurrentRequest().getParameter("encrypt"))) {
+            && "true".equals(Stapler.getCurrentRequest2().getParameter("encrypt"))) {
             return false;
         }
 
@@ -5419,13 +5501,13 @@ public HttpResponse doDoDelete() throws IOException {
 
         @Override
         @POST
-        public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, FormException {
+        public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, FormException {
             Jenkins.get().doConfigExecutorsSubmit(req, rsp);
         }
 
         @WebMethod(name = "config.xml")
         @Override
-        public void doConfigDotXml(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+        public void doConfigDotXml(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
             throw HttpResponses.status(SC_BAD_REQUEST);
         }
 
@@ -5456,7 +5538,7 @@ public List<LogRecord> getLogRecords() throws IOException, InterruptedException
 
         @Override
         @RequirePOST
-        public void doLaunchSlaveAgent(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+        public void doLaunchSlaveAgent(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
             // this computer never returns null from channel, so
             // this method shall never be invoked.
             rsp.sendError(SC_NOT_FOUND);
@@ -5586,7 +5668,7 @@ private static void computeVersion(ServletContext context) {
 
     /**
      * Get the stored version of Jenkins, as stored by
-     * {@link #doConfigSubmit(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse)}.
+     * {@link #doConfigSubmit(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)}.
      * <p>
      * Parses the version into {@link VersionNumber}, or null if it's not parseable as a version number
      * (such as when Jenkins is run with {@code mvn jetty:run})
diff --git a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
index 5aa73c17528a..6725c1f669fb 100644
--- a/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
+++ b/core/src/main/java/jenkins/model/JenkinsLocationConfiguration.java
@@ -12,13 +12,13 @@
 import hudson.model.PersistentDescriptor;
 import hudson.util.FormValidation;
 import hudson.util.XStream2;
+import jakarta.servlet.ServletContext;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
 import jenkins.util.SystemProperties;
 import jenkins.util.UrlHelper;
 import org.jenkinsci.Symbol;
@@ -167,7 +167,7 @@ private boolean isInvalidRootUrl(@Nullable String value) {
      */
     private void updateSecureSessionFlag() {
         try {
-            ServletContext context = Jenkins.get().servletContext;
+            ServletContext context = Jenkins.get().getServletContext();
             Method m;
             try {
                 m = context.getClass().getMethod("getSessionCookieConfig");
@@ -177,7 +177,7 @@ private void updateSecureSessionFlag() {
             }
             Object sessionCookieConfig = m.invoke(context);
 
-            Class scc = Class.forName("javax.servlet.SessionCookieConfig");
+            Class scc = Class.forName("jakarta.servlet.SessionCookieConfig");
             Method setSecure = scc.getMethod("setSecure", boolean.class);
             boolean v = fixNull(jenkinsUrl).startsWith("https");
             setSecure.invoke(sessionCookieConfig, v);
diff --git a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java
index fa95401fb73d..6fefbba1f6af 100644
--- a/core/src/main/java/jenkins/model/MasterBuildConfiguration.java
+++ b/core/src/main/java/jenkins/model/MasterBuildConfiguration.java
@@ -29,7 +29,7 @@
 import java.io.IOException;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Adds the configuration regarding building on the built-in node.
@@ -47,7 +47,7 @@ public String getLabelString() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         Jenkins j = Jenkins.get();
         try {
             // for compatibility reasons, this value is stored in Jenkins
diff --git a/core/src/main/java/jenkins/model/ModelObjectWithChildren.java b/core/src/main/java/jenkins/model/ModelObjectWithChildren.java
index c8d544e03ed8..ed06ea4d7aae 100644
--- a/core/src/main/java/jenkins/model/ModelObjectWithChildren.java
+++ b/core/src/main/java/jenkins/model/ModelObjectWithChildren.java
@@ -1,9 +1,13 @@
 package jenkins.model;
 
+import hudson.Util;
 import hudson.model.ModelObject;
 import jenkins.model.ModelObjectWithContextMenu.ContextMenu;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * {@link ModelObject} that has the children context menu in the breadcrumb.
@@ -20,5 +24,26 @@ public interface ModelObjectWithChildren extends ModelObject {
     /**
      * Generates the context menu to list up all the children.
      */
-    ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception;
+    default ContextMenu doChildrenContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
+        if (Util.isOverridden(ModelObjectWithChildren.class, getClass(), "doChildrenContextMenu", StaplerRequest.class, StaplerResponse.class)) {
+            return doChildrenContextMenu(StaplerRequest.fromStaplerRequest2(request), StaplerResponse.fromStaplerResponse2(response));
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModelObjectWithChildren.class.getSimpleName() + "." + "doChildrenContextMenu" + " methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doChildrenContextMenu(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    default ContextMenu doChildrenContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+        if (Util.isOverridden(ModelObjectWithChildren.class, getClass(), "doChildrenContextMenu", StaplerRequest2.class, StaplerResponse2.class)) {
+            return doChildrenContextMenu(StaplerRequest.toStaplerRequest2(request), StaplerResponse.toStaplerResponse2(response));
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModelObjectWithChildren.class.getSimpleName() + "." + "doChildrenContextMenu" + " methods");
+        }
+    }
 }
diff --git a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
index 26cc3723dabd..2fa50556574c 100644
--- a/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
+++ b/core/src/main/java/jenkins/model/ModelObjectWithContextMenu.java
@@ -2,6 +2,7 @@
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.Functions;
+import hudson.Util;
 import hudson.model.Action;
 import hudson.model.Actionable;
 import hudson.model.BallColor;
@@ -10,14 +11,15 @@
 import hudson.model.ModelObject;
 import hudson.model.Node;
 import hudson.slaves.Cloud;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
-import javax.servlet.ServletException;
 import jenkins.management.Badge;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import org.apache.commons.jelly.JellyContext;
 import org.apache.commons.jelly.JellyException;
 import org.apache.commons.jelly.JellyTagException;
@@ -32,7 +34,9 @@
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
@@ -57,10 +61,31 @@ public interface ModelObjectWithContextMenu extends ModelObject {
      * Generates the context menu.
      *
      * The typical implementation is {@code return new ContextMenu().from(this,request,response);},
-     * which implements the default behaviour. See {@link ContextMenu#from(ModelObjectWithContextMenu, StaplerRequest, StaplerResponse)}
+     * which implements the default behaviour. See {@link ContextMenu#from(ModelObjectWithContextMenu, StaplerRequest2, StaplerResponse2)}
      * for more details of what it does. This should suit most implementations.
      */
-    ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception;
+    default ContextMenu doContextMenu(StaplerRequest2 request, StaplerResponse2 response) throws Exception {
+        if (Util.isOverridden(ModelObjectWithContextMenu.class, getClass(), "doContextMenu", StaplerRequest.class, StaplerResponse.class)) {
+            return doContextMenu(StaplerRequest.fromStaplerRequest2(request), StaplerResponse.fromStaplerResponse2(response));
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModelObjectWithContextMenu.class.getSimpleName() + ".doContextMenu methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #doContextMenu(StaplerRequest2, StaplerResponse2)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    default ContextMenu doContextMenu(StaplerRequest request, StaplerResponse response) throws Exception {
+        if (Util.isOverridden(ModelObjectWithContextMenu.class, getClass(), "doContextMenu", StaplerRequest2.class, StaplerResponse2.class)) {
+            return doContextMenu(StaplerRequest.toStaplerRequest2(request), StaplerResponse.toStaplerResponse2(response));
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the "
+                    + ModelObjectWithContextMenu.class.getSimpleName() + ".doContextMenu methods");
+        }
+    }
 
     /**
      * Data object that represents the context menu.
@@ -76,7 +101,7 @@ class ContextMenu implements HttpResponse {
         public final List<MenuItem> items = new ArrayList<>();
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object o) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object o) throws IOException, ServletException {
             rsp.serveExposedBean(req, this, Flavor.JSON);
         }
 
@@ -98,7 +123,7 @@ public ContextMenu add(Action a) {
             if (!Functions.isContextMenuVisible(a)) {
                 return this;
             }
-            StaplerRequest req = Stapler.getCurrentRequest();
+            StaplerRequest2 req = Stapler.getCurrentRequest2();
             String text = a.getDisplayName();
             String base = Functions.getIconFilePath(a);
             if (base == null)     return this;
@@ -108,7 +133,7 @@ public ContextMenu add(Action a) {
                 Icon icon = Functions.tryGetIcon(base);
                 return add(url, icon.getClassSpec(), text);
             } else {
-                String icon = Stapler.getCurrentRequest().getContextPath() + (base.startsWith("images/") ? Functions.getResourcePath() : "") + '/' + base;
+                String icon = Stapler.getCurrentRequest2().getContextPath() + (base.startsWith("images/") ? Functions.getResourcePath() : "") + '/' + base;
                 return add(url, icon, text);
             }
         }
@@ -267,14 +292,14 @@ public ContextMenu add(Job job) {
          *
          * <p>
          * Unconventional {@link ModelObject} implementations that do not use {@code sidepanel.groovy}
-         * can override {@link ModelObjectWithContextMenu#doContextMenu(StaplerRequest, StaplerResponse)}
+         * can override {@link ModelObjectWithContextMenu#doContextMenu(StaplerRequest2, StaplerResponse2)}
          * directly to provide alternative semantics.
          */
-        public ContextMenu from(ModelObjectWithContextMenu self, StaplerRequest request, StaplerResponse response) throws JellyException, IOException {
+        public ContextMenu from(ModelObjectWithContextMenu self, StaplerRequest2 request, StaplerResponse2 response) throws JellyException, IOException {
             return from(self, request, response, "sidepanel");
         }
 
-        public ContextMenu from(ModelObjectWithContextMenu self, StaplerRequest request, StaplerResponse response, String view) throws JellyException, IOException {
+        public ContextMenu from(ModelObjectWithContextMenu self, StaplerRequest2 request, StaplerResponse2 response, String view) throws JellyException, IOException {
             WebApp webApp = WebApp.getCurrent();
             final Script s = webApp.getMetaClass(self).getTearOff(JellyClassTearOff.class).findScript(view);
             if (s != null) {
@@ -401,9 +426,9 @@ public MenuItem() {
 
         public MenuItem withUrl(String url) {
             try {
-                this.url = new URI(Stapler.getCurrentRequest().getRequestURI()).resolve(new URI(url)).toString();
+                this.url = new URI(Stapler.getCurrentRequest2().getRequestURI()).resolve(new URI(url)).toString();
             } catch (URISyntaxException x) {
-                throw new IllegalArgumentException("Bad URI from " + Stapler.getCurrentRequest().getRequestURI() + " vs. " + url, x);
+                throw new IllegalArgumentException("Bad URI from " + Stapler.getCurrentRequest2().getRequestURI() + " vs. " + url, x);
             }
             return this;
         }
@@ -413,7 +438,7 @@ public MenuItem withUrl(String url) {
          */
         public MenuItem withContextRelativeUrl(String url) {
             if (!url.startsWith("/"))   url = '/' + url;
-            this.url = Stapler.getCurrentRequest().getContextPath() + url;
+            this.url = Stapler.getCurrentRequest2().getContextPath() + url;
             return this;
         }
 
@@ -463,7 +488,7 @@ public MenuItem withDisplayName(ModelObject o) {
         }
 
         private String getResourceUrl() {
-            return Stapler.getCurrentRequest().getContextPath() + Jenkins.RESOURCE_PATH;
+            return Stapler.getCurrentRequest2().getContextPath() + Jenkins.RESOURCE_PATH;
         }
 
     }
@@ -483,7 +508,7 @@ interface ContextMenuVisibility extends Action {
         /**
          * Determines whether to show this action right now.
          * Can always return false, for an action which should never be in the context menu;
-         * or could examine {@link Stapler#getCurrentRequest}.
+         * or could examine {@link Stapler#getCurrentRequest2}.
          * @return true to display it, false to hide
          * @see ContextMenu#add(Action)
          */
diff --git a/core/src/main/java/jenkins/model/OptionalJobProperty.java b/core/src/main/java/jenkins/model/OptionalJobProperty.java
index 2b4db11c1b84..1614f33363b1 100644
--- a/core/src/main/java/jenkins/model/OptionalJobProperty.java
+++ b/core/src/main/java/jenkins/model/OptionalJobProperty.java
@@ -24,11 +24,13 @@
 
 package jenkins.model;
 
+import hudson.Util;
 import hudson.model.Job;
 import hudson.model.JobProperty;
 import hudson.model.JobPropertyDescriptor;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Job property which may or may not be present.
@@ -51,11 +53,23 @@ protected OptionalJobPropertyDescriptor(Class<? extends JobProperty<?>> clazz) {
 
         protected OptionalJobPropertyDescriptor() {}
 
+        @Override
+        public JobProperty<?> newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
+            if (Util.isOverridden(OptionalJobPropertyDescriptor.class, getClass(), "newInstance", StaplerRequest.class, JSONObject.class)) {
+                return newInstance(req != null ? StaplerRequest.fromStaplerRequest2(req) : null, formData);
+            } else {
+                return formData.optBoolean("specified") ? super.newInstance(req, formData) : null;
+            }
+        }
+
+        /**
+         * @deprecated use {@link #newInstance(StaplerRequest2, JSONObject)}
+         */
+        @Deprecated
         @Override
         public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {
             return formData.optBoolean("specified") ? super.newInstance(req, formData) : null;
         }
-
     }
 
 }
diff --git a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java
index 662ffa9359e2..ea8437510818 100644
--- a/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java
+++ b/core/src/main/java/jenkins/model/ParameterizedJobMixIn.java
@@ -24,8 +24,8 @@
 
 package jenkins.model;
 
-import static javax.servlet.http.HttpServletResponse.SC_CONFLICT;
-import static javax.servlet.http.HttpServletResponse.SC_CREATED;
+import static jakarta.servlet.http.HttpServletResponse.SC_CONFLICT;
+import static jakarta.servlet.http.HttpServletResponse.SC_CREATED;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.Util;
@@ -51,14 +51,16 @@
 import hudson.triggers.Trigger;
 import hudson.util.AlternativeUiTextProvider;
 import hudson.views.BuildButtonColumn;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
-import javax.servlet.ServletException;
 import jenkins.model.lazy.LazyBuildMixIn;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.triggers.SCMTriggerItem;
 import jenkins.triggers.TriggeredItem;
 import jenkins.util.TimeDuration;
@@ -73,7 +75,9 @@
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 /**
@@ -191,7 +195,7 @@ public final boolean isParameterized() {
      * Standard implementation of {@link ParameterizedJob#doBuild}.
      */
     @SuppressWarnings("deprecation")
-    public final void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
+    public final void doBuild(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
         if (delay == null) {
             delay = new TimeDuration(TimeUnit.MILLISECONDS.convert(asJob().getQuietPeriod(), TimeUnit.SECONDS));
         }
@@ -229,7 +233,7 @@ public final void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParamet
      * Standard implementation of {@link ParameterizedJob#doBuildWithParameters}.
      */
     @SuppressWarnings("deprecation")
-    public final void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
+    public final void doBuildWithParameters(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
         BuildAuthorizationToken.checkPermission(asJob(), asJob().getAuthToken(), req, rsp);
 
         ParametersDefinitionProperty pp = asJob().getProperty(ParametersDefinitionProperty.class);
@@ -247,7 +251,7 @@ public final void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp,
      * Standard implementation of {@link ParameterizedJob#doCancelQueue}.
      */
     @RequirePOST
-    public final void doCancelQueue(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+    public final void doCancelQueue(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
         asJob().checkPermission(Item.CANCEL);
         Jenkins.get().getQueue().cancel(asJob());
         rsp.forwardToPreviousPage(req);
@@ -269,7 +273,7 @@ public final SearchIndexBuilder extendSearchIndex(SearchIndexBuilder sib) {
      * Computes the build cause, using RemoteCause or UserCause as appropriate.
      */
     @Restricted(NoExternalUse.class)
-    public static CauseAction getBuildCause(ParameterizedJob job, StaplerRequest req) {
+    public static CauseAction getBuildCause(ParameterizedJob job, StaplerRequest2 req) {
         Cause cause;
         @SuppressWarnings("deprecation")
         BuildAuthorizationToken authToken = job.getAuthToken();
@@ -401,8 +405,29 @@ default QueueTaskFuture<RunT> scheduleBuild2(int quietPeriod, Action... actions)
          * Schedules a new build command.
          * @see ParameterizedJobMixIn#doBuild
          */
-        default void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
-            getParameterizedJobMixIn().doBuild(req, rsp, delay);
+        default void doBuild(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
+            if (Util.isOverridden(ParameterizedJob.class, getClass(), "doBuild", StaplerRequest.class, StaplerResponse.class, TimeDuration.class)) {
+                try {
+                    doBuild(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp), delay);
+                } catch (javax.servlet.ServletException e) {
+                    throw ServletExceptionWrapper.toJakartaServletException(e);
+                }
+            } else {
+                getParameterizedJobMixIn().doBuild(req, rsp, delay);
+            }
+        }
+
+        /**
+         * @deprecated use {@link #doBuild(StaplerRequest2, StaplerResponse2, TimeDuration)}
+         */
+        @Deprecated
+        @StaplerNotDispatchable
+        default void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, javax.servlet.ServletException {
+            try {
+                getParameterizedJobMixIn().doBuild(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), delay);
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
         }
 
         /**
@@ -410,8 +435,29 @@ default void doBuild(StaplerRequest req, StaplerResponse rsp, @QueryParameter Ti
          * Currently only String parameters are supported.
          * @see ParameterizedJobMixIn#doBuildWithParameters
          */
-        default void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
-            getParameterizedJobMixIn().doBuildWithParameters(req, rsp, delay);
+        default void doBuildWithParameters(StaplerRequest2 req, StaplerResponse2 rsp, @QueryParameter TimeDuration delay) throws IOException, ServletException {
+            if (Util.isOverridden(ParameterizedJob.class, getClass(), "doBuildWithParameters", StaplerRequest.class, StaplerResponse.class, TimeDuration.class)) {
+                try {
+                    doBuildWithParameters(StaplerRequest.fromStaplerRequest2(req), StaplerResponse.fromStaplerResponse2(rsp), delay);
+                } catch (javax.servlet.ServletException e) {
+                    throw ServletExceptionWrapper.toJakartaServletException(e);
+                }
+            } else {
+                getParameterizedJobMixIn().doBuildWithParameters(req, rsp, delay);
+            }
+        }
+
+        /**
+         * @deprecated use {@link #doBuildWithParameters(StaplerRequest2, StaplerResponse2, TimeDuration)}
+         */
+        @Deprecated
+        @StaplerNotDispatchable
+        default void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @QueryParameter TimeDuration delay) throws IOException, javax.servlet.ServletException {
+            try {
+                getParameterizedJobMixIn().doBuildWithParameters(StaplerRequest.toStaplerRequest2(req), StaplerResponse.toStaplerResponse2(rsp), delay);
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
         }
 
         /**
@@ -419,7 +465,7 @@ default void doBuildWithParameters(StaplerRequest req, StaplerResponse rsp, @Que
          * @see ParameterizedJobMixIn#doCancelQueue
          */
         @RequirePOST
-        default void doCancelQueue(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+        default void doCancelQueue(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
             getParameterizedJobMixIn().doCancelQueue(req, rsp);
         }
 
@@ -427,7 +473,7 @@ default void doCancelQueue(StaplerRequest req, StaplerResponse rsp) throws IOExc
          * Schedules a new SCM polling command.
          */
         @SuppressWarnings("deprecation")
-        default void doPolling(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
+        default void doPolling(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException {
             if (!(this instanceof SCMTriggerItem)) {
                 rsp.sendError(404);
                 return;
@@ -485,7 +531,7 @@ default void makeDisabled(boolean b) throws IOException {
 
         @CLIMethod(name = "disable-job")
         @RequirePOST
-        default HttpResponse doDisable() throws IOException, ServletException {
+        default HttpResponse doDisable() throws IOException {
             checkPermission(CONFIGURE);
             makeDisabled(true);
             return new HttpRedirect(".");
@@ -493,7 +539,7 @@ default HttpResponse doDisable() throws IOException, ServletException {
 
         @CLIMethod(name = "enable-job")
         @RequirePOST
-        default HttpResponse doEnable() throws IOException, ServletException {
+        default HttpResponse doEnable() throws IOException {
             checkPermission(CONFIGURE);
             makeDisabled(false);
             return new HttpRedirect(".");
diff --git a/core/src/main/java/jenkins/model/ProjectNamingStrategy.java b/core/src/main/java/jenkins/model/ProjectNamingStrategy.java
index 76e9ff64587f..796519f7d9c8 100644
--- a/core/src/main/java/jenkins/model/ProjectNamingStrategy.java
+++ b/core/src/main/java/jenkins/model/ProjectNamingStrategy.java
@@ -33,11 +33,11 @@
 import hudson.model.Descriptor;
 import hudson.model.Failure;
 import hudson.util.FormValidation;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
-import javax.servlet.ServletException;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.QueryParameter;
diff --git a/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java b/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java
index 85332d26973c..06d1a7696e66 100644
--- a/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java
+++ b/core/src/main/java/jenkins/model/experimentalflags/UserExperimentalFlagsProperty.java
@@ -37,7 +37,7 @@
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 
 /**
@@ -74,7 +74,7 @@ public static final class DescriptorImpl extends UserPropertyDescriptor {
         }
 
         @Override
-        public UserProperty newInstance(@Nullable StaplerRequest req, @NonNull JSONObject formData) throws FormException {
+        public UserProperty newInstance(@Nullable StaplerRequest2 req, @NonNull JSONObject formData) throws FormException {
             JSONObject flagsObj = formData.getJSONObject("flags");
             Map<String, String> flags = new HashMap<>();
             for (String key : flagsObj.keySet()) {
diff --git a/core/src/main/java/jenkins/model/item_category/Categories.java b/core/src/main/java/jenkins/model/item_category/Categories.java
index fd9b475cdf10..9e80eb0085fb 100644
--- a/core/src/main/java/jenkins/model/item_category/Categories.java
+++ b/core/src/main/java/jenkins/model/item_category/Categories.java
@@ -26,16 +26,16 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.ArrayList;
 import java.util.List;
-import javax.servlet.ServletException;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.export.Exported;
 import org.kohsuke.stapler.export.ExportedBean;
 import org.kohsuke.stapler.export.Flavor;
@@ -63,7 +63,7 @@ public List<Category> getItems() {
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
         rsp.serveExposedBean(req, this, Flavor.JSON);
     }
 
diff --git a/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java b/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java
index 06aad8ed9ef5..98055fb39b2e 100644
--- a/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java
+++ b/core/src/main/java/jenkins/mvn/GlobalSettingsProvider.java
@@ -6,9 +6,11 @@
 import hudson.model.AbstractDescribableImpl;
 import hudson.model.Descriptor;
 import hudson.model.TaskListener;
-import javax.servlet.ServletException;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
@@ -26,7 +28,10 @@ public abstract class GlobalSettingsProvider extends AbstractDescribableImpl<Glo
      */
     public abstract FilePath supplySettings(AbstractBuild<?, ?> build, TaskListener listener);
 
-    public static GlobalSettingsProvider parseSettingsProvider(StaplerRequest req) throws Descriptor.FormException, ServletException {
+    /**
+     * @since TODO
+     */
+    public static GlobalSettingsProvider parseSettingsProvider(StaplerRequest2 req) throws Descriptor.FormException, ServletException {
         JSONObject settings = req.getSubmittedForm().getJSONObject("globalSettings");
         if (settings == null) {
             return new DefaultGlobalSettingsProvider();
@@ -34,6 +39,18 @@ public static GlobalSettingsProvider parseSettingsProvider(StaplerRequest req) t
         return req.bindJSON(GlobalSettingsProvider.class, settings);
     }
 
+    /**
+     * @deprecated use {@link #parseSettingsProvider(StaplerRequest2)}
+     */
+    @Deprecated
+    public static GlobalSettingsProvider parseSettingsProvider(StaplerRequest req) throws Descriptor.FormException, javax.servlet.ServletException {
+        try {
+            return parseSettingsProvider(StaplerRequest.toStaplerRequest2(req));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Convenience method handling all {@code null} checks. Provides the path on the (possible) remote settings file.
      *
diff --git a/core/src/main/java/jenkins/mvn/SettingsProvider.java b/core/src/main/java/jenkins/mvn/SettingsProvider.java
index 266f9c1cd00c..9173c5dbadf5 100644
--- a/core/src/main/java/jenkins/mvn/SettingsProvider.java
+++ b/core/src/main/java/jenkins/mvn/SettingsProvider.java
@@ -6,9 +6,11 @@
 import hudson.model.AbstractDescribableImpl;
 import hudson.model.Descriptor;
 import hudson.model.TaskListener;
-import javax.servlet.ServletException;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import jakarta.servlet.ServletException;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author <a href="mailto:nicolas.deloof@gmail.com">Nicolas De Loof</a>
@@ -24,7 +26,7 @@ public abstract class SettingsProvider extends AbstractDescribableImpl<SettingsP
      */
     public abstract FilePath supplySettings(AbstractBuild<?, ?> build, TaskListener listener);
 
-    public static SettingsProvider parseSettingsProvider(StaplerRequest req) throws Descriptor.FormException, ServletException {
+    public static SettingsProvider parseSettingsProvider(StaplerRequest2 req) throws Descriptor.FormException, ServletException {
         JSONObject settings = req.getSubmittedForm().getJSONObject("settings");
         if (settings == null) {
             return new DefaultSettingsProvider();
@@ -32,6 +34,18 @@ public static SettingsProvider parseSettingsProvider(StaplerRequest req) throws
         return req.bindJSON(SettingsProvider.class, settings);
     }
 
+    /**
+     * @deprecated use {@link #parseSettingsProvider(StaplerRequest2)}
+     */
+    @Deprecated
+    public static SettingsProvider parseSettingsProvider(StaplerRequest req) throws Descriptor.FormException, javax.servlet.ServletException {
+        try {
+            return parseSettingsProvider(StaplerRequest.toStaplerRequest2(req));
+        } catch (ServletException e) {
+            throw ServletExceptionWrapper.fromJakartaServletException(e);
+        }
+    }
+
     /**
      * Convenience method handling all {@code null} checks. Provides the path on the (possible) remote settings file.
      *
diff --git a/core/src/main/java/jenkins/security/AcegiSecurityExceptionFilter.java b/core/src/main/java/jenkins/security/AcegiSecurityExceptionFilter.java
index 5aec5265e166..1441ae5a6165 100644
--- a/core/src/main/java/jenkins/security/AcegiSecurityExceptionFilter.java
+++ b/core/src/main/java/jenkins/security/AcegiSecurityExceptionFilter.java
@@ -26,17 +26,17 @@
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.security.UnwrapSecurityExceptionFilter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
 import java.io.IOException;
 import java.util.function.Function;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
 import org.acegisecurity.AcegiSecurityException;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
 
 /**
@@ -44,7 +44,7 @@
  * Used by other filters like {@link UnwrapSecurityExceptionFilter} and {@link ExceptionTranslationFilter}.
  */
 @Restricted(NoExternalUse.class)
-public class AcegiSecurityExceptionFilter implements Filter {
+public class AcegiSecurityExceptionFilter implements CompatibleFilter {
 
     @Override
     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
diff --git a/core/src/main/java/jenkins/security/ApiCrumbExclusion.java b/core/src/main/java/jenkins/security/ApiCrumbExclusion.java
index 926eec501882..f001950d3464 100644
--- a/core/src/main/java/jenkins/security/ApiCrumbExclusion.java
+++ b/core/src/main/java/jenkins/security/ApiCrumbExclusion.java
@@ -26,11 +26,11 @@
 
 import hudson.Extension;
 import hudson.security.csrf.CrumbExclusion;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
diff --git a/core/src/main/java/jenkins/security/ApiTokenFilter.java b/core/src/main/java/jenkins/security/ApiTokenFilter.java
index 986408d62604..355c32d9e254 100644
--- a/core/src/main/java/jenkins/security/ApiTokenFilter.java
+++ b/core/src/main/java/jenkins/security/ApiTokenFilter.java
@@ -1,7 +1,7 @@
 package jenkins.security;
 
+import jakarta.servlet.Filter;
 import java.util.List;
-import javax.servlet.Filter;
 
 /**
  * {@link Filter} that performs HTTP basic authentication based on API token.
diff --git a/core/src/main/java/jenkins/security/ApiTokenProperty.java b/core/src/main/java/jenkins/security/ApiTokenProperty.java
index 464fdcbdf16c..804b8edbc56e 100644
--- a/core/src/main/java/jenkins/security/ApiTokenProperty.java
+++ b/core/src/main/java/jenkins/security/ApiTokenProperty.java
@@ -66,7 +66,7 @@
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
@@ -274,7 +274,7 @@ public TokenInfoAndStats(@NonNull ApiTokenStore.HashedToken token, @NonNull ApiT
      * Allow user to rename tokens
      */
     @Override
-    public UserProperty reconfigure(StaplerRequest req, @CheckForNull JSONObject form) throws FormException {
+    public UserProperty reconfigure(StaplerRequest2 req, @CheckForNull JSONObject form) throws FormException {
         if (form == null) {
             return this;
         }
diff --git a/core/src/main/java/jenkins/security/AuthenticationSuccessHandler.java b/core/src/main/java/jenkins/security/AuthenticationSuccessHandler.java
index a5c7cffceeb8..a9dc6ef787b4 100644
--- a/core/src/main/java/jenkins/security/AuthenticationSuccessHandler.java
+++ b/core/src/main/java/jenkins/security/AuthenticationSuccessHandler.java
@@ -25,8 +25,8 @@
 package jenkins.security;
 
 import hudson.Util;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.springframework.security.core.Authentication;
diff --git a/core/src/main/java/jenkins/security/BasicHeaderApiTokenAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderApiTokenAuthenticator.java
index d37a59755725..5aab6868ea56 100644
--- a/core/src/main/java/jenkins/security/BasicHeaderApiTokenAuthenticator.java
+++ b/core/src/main/java/jenkins/security/BasicHeaderApiTokenAuthenticator.java
@@ -4,10 +4,10 @@
 
 import hudson.Extension;
 import hudson.model.User;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.springframework.security.core.Authentication;
diff --git a/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java
index 471e0d3900c7..2906a1aa461b 100644
--- a/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java
+++ b/core/src/main/java/jenkins/security/BasicHeaderAuthenticator.java
@@ -4,10 +4,13 @@
 import hudson.ExtensionList;
 import hudson.ExtensionPoint;
 import hudson.Util;
+import io.jenkins.servlet.ServletExceptionWrapper;
+import io.jenkins.servlet.http.HttpServletRequestWrapper;
+import io.jenkins.servlet.http.HttpServletResponseWrapper;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.springframework.security.core.Authentication;
 
 /**
@@ -35,11 +38,42 @@ public abstract class BasicHeaderAuthenticator implements ExtensionPoint {
      * <p>
      * When no processor can validate the username/password pair, caller will make
      * the request processing fail.
-     * @since 2.266
+     * @since TODO
      */
     @CheckForNull
     public Authentication authenticate2(HttpServletRequest req, HttpServletResponse rsp, String username, String password) throws IOException, ServletException {
-        if (Util.isOverridden(BasicHeaderAuthenticator.class, getClass(), "authenticate", HttpServletRequest.class, HttpServletResponse.class, String.class, String.class)) {
+        if (Util.isOverridden(BasicHeaderAuthenticator.class, getClass(), "authenticate2", javax.servlet.http.HttpServletRequest.class, javax.servlet.http.HttpServletResponse.class, String.class, String.class)) {
+            try {
+                return authenticate2(HttpServletRequestWrapper.fromJakartaHttpServletRequest(req), HttpServletResponseWrapper.fromJakartaHttpServletResponse(rsp), username, password);
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else if (Util.isOverridden(BasicHeaderAuthenticator.class, getClass(), "authenticate", javax.servlet.http.HttpServletRequest.class, javax.servlet.http.HttpServletResponse.class, String.class, String.class)) {
+            try {
+                org.acegisecurity.Authentication a = authenticate(HttpServletRequestWrapper.fromJakartaHttpServletRequest(req), HttpServletResponseWrapper.fromJakartaHttpServletResponse(rsp), username, password);
+                return a != null ? a.toSpring() : null;
+            } catch (javax.servlet.ServletException e) {
+                throw ServletExceptionWrapper.toJakartaServletException(e);
+            }
+        } else {
+            throw new AbstractMethodError("The class " + getClass().getName() + " must override at least one of the " + BasicHeaderAuthenticator.class.getSimpleName() + ".authenticate2 methods");
+        }
+    }
+
+    /**
+     * @deprecated use {@link #authenticate2(HttpServletRequest, HttpServletResponse, String, String)}
+     * @since 2.266
+     */
+    @CheckForNull
+    @Deprecated
+    public Authentication authenticate2(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse rsp, String username, String password) throws IOException, javax.servlet.ServletException {
+        if (Util.isOverridden(BasicHeaderAuthenticator.class, getClass(), "authenticate2", HttpServletRequest.class, HttpServletResponse.class, String.class, String.class)) {
+            try {
+                return authenticate2(HttpServletRequestWrapper.toJakartaHttpServletRequest(req), HttpServletResponseWrapper.toJakartaHttpServletResponse(rsp), username, password);
+            } catch (ServletException e) {
+                throw ServletExceptionWrapper.fromJakartaServletException(e);
+            }
+        } else if (Util.isOverridden(BasicHeaderAuthenticator.class, getClass(), "authenticate", javax.servlet.http.HttpServletRequest.class, javax.servlet.http.HttpServletResponse.class, String.class, String.class)) {
             org.acegisecurity.Authentication a = authenticate(req, rsp, username, password);
             return a != null ? a.toSpring() : null;
         } else {
@@ -52,7 +86,7 @@ public Authentication authenticate2(HttpServletRequest req, HttpServletResponse
      */
     @Deprecated
     @CheckForNull
-    public org.acegisecurity.Authentication authenticate(HttpServletRequest req, HttpServletResponse rsp, String username, String password) throws IOException, ServletException {
+    public org.acegisecurity.Authentication authenticate(javax.servlet.http.HttpServletRequest req, javax.servlet.http.HttpServletResponse rsp, String username, String password) throws IOException, javax.servlet.ServletException {
         Authentication a = authenticate2(req, rsp, username, password);
         return a != null ? org.acegisecurity.Authentication.fromSpring(a) : null;
     }
diff --git a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java
index 45b5eb0c70a2..1b31dba65e42 100644
--- a/core/src/main/java/jenkins/security/BasicHeaderProcessor.java
+++ b/core/src/main/java/jenkins/security/BasicHeaderProcessor.java
@@ -7,20 +7,21 @@
 import hudson.security.ACLContext;
 import hudson.security.SecurityRealm;
 import hudson.util.Scrambler;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.List;
 import java.util.Locale;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 import org.springframework.security.authentication.AnonymousAuthenticationToken;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -43,7 +44,7 @@
  * @author Kohsuke Kawaguchi
  */
 @Restricted(NoExternalUse.class)
-public class BasicHeaderProcessor implements Filter {
+public class BasicHeaderProcessor implements CompatibleFilter {
     private AuthenticationEntryPoint authenticationEntryPoint;
     private RememberMeServices rememberMeServices = new NullRememberMeServices();
 
diff --git a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java
index 1007819c981a..70ef36505683 100644
--- a/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java
+++ b/core/src/main/java/jenkins/security/BasicHeaderRealPasswordAuthenticator.java
@@ -19,11 +19,11 @@
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.Extension;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.ExtensionFilter;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
diff --git a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java
index cb8b8accf295..31951b8572fb 100644
--- a/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java
+++ b/core/src/main/java/jenkins/security/LastGrantedAuthoritiesProperty.java
@@ -21,7 +21,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
@@ -44,7 +44,7 @@ public class LastGrantedAuthoritiesProperty extends UserProperty {
      * Stick to the same object since there's no UI for this.
      */
     @Override
-    public UserProperty reconfigure(StaplerRequest req, JSONObject form) throws FormException {
+    public UserProperty reconfigure(StaplerRequest2 req, JSONObject form) throws FormException {
         req.bindJSON(this, form);
         return this;
     }
diff --git a/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java b/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java
index e67e73b8db33..859b0db4ef1b 100644
--- a/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java
+++ b/core/src/main/java/jenkins/security/NonSerializableSecurityContext.java
@@ -16,7 +16,7 @@
 package jenkins.security;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
-import javax.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSession;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.springframework.security.core.Authentication;
diff --git a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java
index b4c033bfad0e..b409d92d9490 100644
--- a/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java
+++ b/core/src/main/java/jenkins/security/QueueItemAuthenticatorConfiguration.java
@@ -11,7 +11,7 @@
 import jenkins.model.GlobalConfigurationCategory;
 import net.sf.json.JSONObject;
 import org.jenkinsci.Symbol;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Show the {@link QueueItemAuthenticator} configurations on the system config page.
@@ -47,7 +47,7 @@ public DescribableList<QueueItemAuthenticator, QueueItemAuthenticatorDescriptor>
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             authenticators.rebuildHetero(req, json, QueueItemAuthenticatorDescriptor.all(), "authenticators");
             return true;
diff --git a/core/src/main/java/jenkins/security/ResourceDomainConfiguration.java b/core/src/main/java/jenkins/security/ResourceDomainConfiguration.java
index cd552fc65130..6b03113019d5 100644
--- a/core/src/main/java/jenkins/security/ResourceDomainConfiguration.java
+++ b/core/src/main/java/jenkins/security/ResourceDomainConfiguration.java
@@ -31,6 +31,7 @@
 import hudson.ExtensionList;
 import hudson.Util;
 import hudson.util.FormValidation;
+import jakarta.servlet.http.HttpServletRequest;
 import java.io.IOException;
 import java.net.HttpURLConnection;
 import java.net.MalformedURLException;
@@ -43,7 +44,6 @@
 import java.util.Base64;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.http.HttpServletRequest;
 import jenkins.diagnostics.RootUrlNotSetMonitor;
 import jenkins.model.GlobalConfiguration;
 import jenkins.model.Jenkins;
@@ -57,7 +57,7 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.verb.POST;
 
 /**
@@ -134,7 +134,7 @@ private FormValidation checkUrl(String resourceRootUrlString, boolean allowOnlin
             return FormValidation.error(Messages.ResourceDomainConfiguration_InvalidRootURL(ex.getMessage()));
         }
 
-        StaplerRequest currentRequest = Stapler.getCurrentRequest();
+        StaplerRequest2 currentRequest = Stapler.getCurrentRequest2();
         if (currentRequest != null) {
             String currentRequestHost = currentRequest.getServerName();
 
diff --git a/core/src/main/java/jenkins/security/ResourceDomainFilter.java b/core/src/main/java/jenkins/security/ResourceDomainFilter.java
index b88fc7045ff6..4e47dbb2e5cd 100644
--- a/core/src/main/java/jenkins/security/ResourceDomainFilter.java
+++ b/core/src/main/java/jenkins/security/ResourceDomainFilter.java
@@ -26,14 +26,14 @@
 
 import hudson.Extension;
 import hudson.Functions;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Set;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.util.HttpServletFilter;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
diff --git a/core/src/main/java/jenkins/security/ResourceDomainRootAction.java b/core/src/main/java/jenkins/security/ResourceDomainRootAction.java
index fc18071fade7..bd327599bd2f 100644
--- a/core/src/main/java/jenkins/security/ResourceDomainRootAction.java
+++ b/core/src/main/java/jenkins/security/ResourceDomainRootAction.java
@@ -54,8 +54,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.access.AccessDeniedException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.userdetails.UsernameNotFoundException;
@@ -101,7 +101,7 @@ public static ResourceDomainRootAction get() {
         return ExtensionList.lookupSingleton(ResourceDomainRootAction.class);
     }
 
-    public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException {
+    public void doIndex(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
         if (ResourceDomainConfiguration.isResourceRequest(req)) {
             rsp.sendError(404, ResourceDomainFilter.ERROR_RESPONSE);
         } else {
@@ -110,7 +110,7 @@ public void doIndex(StaplerRequest req, StaplerResponse rsp) throws IOException
         }
     }
 
-    public Object getDynamic(String id, StaplerRequest req, StaplerResponse rsp) throws Exception {
+    public Object getDynamic(String id, StaplerRequest2 req, StaplerResponse2 rsp) throws Exception {
         if (!ResourceDomainConfiguration.isResourceRequest(req)) {
             req.setAttribute(RESOURCE_DOMAIN_ROOT_ACTION_ERROR, true);
             rsp.sendError(404, "Cannot handle requests to this URL unless on Jenkins resource URL.");
@@ -147,7 +147,7 @@ private Redirection(String url) {
             this.url = url;
         }
 
-        public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             String restOfPath = req.getRestOfPath();
 
             String url = Jenkins.get().getRootUrl() + this.url + restOfPath;
@@ -169,7 +169,7 @@ private static String getResourceRootUrl() {
     }
 
     /**
-     * Called from {@link DirectoryBrowserSupport#generateResponse(StaplerRequest, StaplerResponse, Object)} to obtain
+     * Called from {@link DirectoryBrowserSupport#generateResponse(StaplerRequest2, StaplerResponse2, Object)} to obtain
      * a token to use when rendering a response.
      *
      * @param dbs the {@link DirectoryBrowserSupport} instance requesting the token
@@ -177,7 +177,7 @@ private static String getResourceRootUrl() {
      * @return a token that can be used to redirect users to the {@link ResourceDomainRootAction}.
      */
     @CheckForNull
-    public Token getToken(@NonNull DirectoryBrowserSupport dbs, @NonNull StaplerRequest req) {
+    public Token getToken(@NonNull DirectoryBrowserSupport dbs, @NonNull StaplerRequest2 req) {
         // This is the "restOfPath" of the DirectoryBrowserSupport, i.e. the directory/file/pattern "inside" the DBS.
         final String dbsFile = req.getOriginalRestOfPath();
 
@@ -212,7 +212,7 @@ private static class InternalResourceRequest {
             this.authenticationName = authenticationName;
         }
 
-        public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws IOException {
+        public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException {
             String restOfPath = req.getRestOfPath();
 
             String requestUrlSuffix = this.browserUrl;
diff --git a/core/src/main/java/jenkins/security/SecureRequester.java b/core/src/main/java/jenkins/security/SecureRequester.java
index 18c634a155ac..489deccab1fd 100644
--- a/core/src/main/java/jenkins/security/SecureRequester.java
+++ b/core/src/main/java/jenkins/security/SecureRequester.java
@@ -2,13 +2,16 @@
 
 import hudson.Extension;
 import hudson.ExtensionPoint;
+import hudson.Util;
 import hudson.model.Api;
 import java.util.logging.Logger;
 import jenkins.model.Jenkins;
+import jenkins.security.stapler.StaplerNotDispatchable;
 import jenkins.util.SystemProperties;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * An extension point for authorizing REST API access to an object where an unsafe result type would be produced.
@@ -22,13 +25,37 @@ public interface SecureRequester extends ExtensionPoint {
 
     /**
      * Checks if a Jenkins object can be accessed by a given REST request.
-     * For instance, if the {@link StaplerRequest#getReferer} matches a given host, or
+     * For instance, if the {@link StaplerRequest2#getReferer} matches a given host, or
      * anonymous read is allowed for the given object.
      * @param req a request going through the REST API
      * @param bean an exported object of some kind
      * @return true if this requester should be trusted, false to reject
      */
-    boolean permit(StaplerRequest req, Object bean);
+    @StaplerNotDispatchable
+    default boolean permit(StaplerRequest2 req, Object bean) {
+        return Util.ifOverridden(
+                () -> permit(StaplerRequest.fromStaplerRequest2(req), bean),
+                SecureRequester.class,
+                getClass(),
+                "permit",
+                StaplerRequest.class,
+                Object.class);
+    }
+
+    /**
+     * @deprecated use {@link #permit(StaplerRequest2, Object)}
+     */
+    @Deprecated
+    @StaplerNotDispatchable
+    default boolean permit(StaplerRequest req, Object bean) {
+        return Util.ifOverridden(
+                () -> permit(StaplerRequest.toStaplerRequest2(req), bean),
+                SecureRequester.class,
+                getClass(),
+                "permit",
+                StaplerRequest2.class,
+                Object.class);
+    }
 
     @Restricted(NoExternalUse.class)
     @Extension class Default implements SecureRequester {
@@ -42,7 +69,7 @@ public interface SecureRequester extends ExtensionPoint {
             }
         }
 
-        @Override public boolean permit(StaplerRequest req, Object bean) {
+        @Override public boolean permit(StaplerRequest2 req, Object bean) {
             return INSECURE || !Jenkins.get().isUseSecurity();
         }
 
diff --git a/core/src/main/java/jenkins/security/SuspiciousRequestFilter.java b/core/src/main/java/jenkins/security/SuspiciousRequestFilter.java
index 9b9f413606d8..26a1eb5da845 100644
--- a/core/src/main/java/jenkins/security/SuspiciousRequestFilter.java
+++ b/core/src/main/java/jenkins/security/SuspiciousRequestFilter.java
@@ -1,22 +1,22 @@
 package jenkins.security;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.util.logging.Logger;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.util.SystemProperties;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 @Restricted(NoExternalUse.class)
-public class SuspiciousRequestFilter implements Filter {
+public class SuspiciousRequestFilter implements CompatibleFilter {
 
     /** System property name set to true or false to indicate whether or not semicolons should be allowed in URL paths. */
     public static final String ALLOW_SEMICOLONS_IN_PATH = SuspiciousRequestFilter.class.getName() + ".allowSemicolonsInPath";
diff --git a/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java b/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java
index da4fc322811e..33638a3c9d65 100644
--- a/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java
+++ b/core/src/main/java/jenkins/security/UpdateSiteWarningsConfiguration.java
@@ -40,7 +40,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundSetter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Configuration for update site-provided warnings.
@@ -111,7 +111,7 @@ public Set<UpdateSite.Warning> getApplicableWarnings() {
 
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         HashSet<String> newIgnoredWarnings = new HashSet<>();
         for (Object key : json.keySet()) {
             String warningKey = key.toString();
diff --git a/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java b/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java
index 1996a5efc174..870e6d7de342 100644
--- a/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java
+++ b/core/src/main/java/jenkins/security/seed/UserSeedSecurityListener.java
@@ -27,12 +27,12 @@
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Extension;
 import hudson.model.User;
-import javax.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSession;
 import jenkins.security.SecurityListener;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.core.userdetails.UserDetails;
 
 /**
@@ -53,7 +53,7 @@ protected void authenticated2(@NonNull UserDetails details) {
     }
 
     private static void putUserSeedInSession(String username, boolean overwriteSessionSeed) {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req == null) {
             // expected case: CLI
             // But also HudsonPrivateSecurityRealm because of a redirect from Spring Security, the request is not a Stapler one
diff --git a/core/src/main/java/jenkins/security/stapler/StaplerDispatchValidator.java b/core/src/main/java/jenkins/security/stapler/StaplerDispatchValidator.java
index eebfcfdacf0e..028b2dba1db3 100644
--- a/core/src/main/java/jenkins/security/stapler/StaplerDispatchValidator.java
+++ b/core/src/main/java/jenkins/security/stapler/StaplerDispatchValidator.java
@@ -28,6 +28,7 @@
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import edu.umd.cs.findbugs.annotations.NonNull;
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+import jakarta.servlet.ServletContext;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -50,7 +51,6 @@
 import java.util.function.Supplier;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
 import jenkins.YesNoMaybe;
 import jenkins.model.Jenkins;
 import jenkins.util.SystemProperties;
@@ -59,8 +59,8 @@
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.CancelRequestHandlingException;
 import org.kohsuke.stapler.DispatchValidator;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 
 /**
@@ -95,7 +95,7 @@ public class StaplerDispatchValidator implements DispatchValidator {
     public static /* script-console editable */ boolean DISABLED = SystemProperties.getBoolean(ESCAPE_HATCH);
 
     @NonNull
-    private static YesNoMaybe setStatus(@NonNull StaplerRequest req, @NonNull YesNoMaybe status) {
+    private static YesNoMaybe setStatus(@NonNull StaplerRequest2 req, @NonNull YesNoMaybe status) {
         switch (status) {
             case YES:
             case NO:
@@ -110,7 +110,7 @@ private static YesNoMaybe setStatus(@NonNull StaplerRequest req, @NonNull YesNoM
     }
 
     @NonNull
-    private static YesNoMaybe computeStatusIfNull(@NonNull StaplerRequest req, @NonNull Supplier<YesNoMaybe> statusIfNull) {
+    private static YesNoMaybe computeStatusIfNull(@NonNull StaplerRequest2 req, @NonNull Supplier<YesNoMaybe> statusIfNull) {
         Object requestStatus = req.getAttribute(ATTRIBUTE_NAME);
         if (requestStatus instanceof Boolean) {
             return (Boolean) requestStatus ? YesNoMaybe.YES : YesNoMaybe.NO;
@@ -127,7 +127,7 @@ public StaplerDispatchValidator() {
     }
 
     @Override
-    public @CheckForNull Boolean isDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) {
+    public @CheckForNull Boolean isDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) {
         if (DISABLED) {
             return true;
         }
@@ -145,7 +145,7 @@ public StaplerDispatchValidator() {
     }
 
     @Override
-    public @CheckForNull Boolean isDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp, @NonNull String viewName, @CheckForNull Object node) {
+    public @CheckForNull Boolean isDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp, @NonNull String viewName, @CheckForNull Object node) {
         if (DISABLED) {
             return true;
         }
@@ -163,7 +163,7 @@ public StaplerDispatchValidator() {
     }
 
     @Override
-    public void allowDispatch(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) {
+    public void allowDispatch(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) {
         if (DISABLED) {
             return;
         }
@@ -171,7 +171,7 @@ public void allowDispatch(@NonNull StaplerRequest req, @NonNull StaplerResponse
     }
 
     @Override
-    public void requireDispatchAllowed(@NonNull StaplerRequest req, @NonNull StaplerResponse rsp) throws CancelRequestHandlingException {
+    public void requireDispatchAllowed(@NonNull StaplerRequest2 req, @NonNull StaplerResponse2 rsp) throws CancelRequestHandlingException {
         if (DISABLED) {
             return;
         }
diff --git a/core/src/main/java/jenkins/security/stapler/StaplerFilteredActionListener.java b/core/src/main/java/jenkins/security/stapler/StaplerFilteredActionListener.java
index cc658c275fcf..ad8837c19d83 100644
--- a/core/src/main/java/jenkins/security/stapler/StaplerFilteredActionListener.java
+++ b/core/src/main/java/jenkins/security/stapler/StaplerFilteredActionListener.java
@@ -29,8 +29,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.Function;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.event.FilteredDispatchTriggerListener;
 import org.kohsuke.stapler.event.FilteredDoActionTriggerListener;
 import org.kohsuke.stapler.event.FilteredFieldTriggerListener;
@@ -49,7 +49,7 @@ public class StaplerFilteredActionListener implements FilteredDoActionTriggerLis
             "Learn more: https://www.jenkins.io/redirect/stapler-routing";
 
     @Override
-    public boolean onDoActionTrigger(Function f, StaplerRequest req, StaplerResponse rsp, Object node) {
+    public boolean onDoActionTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node) {
         LOGGER.log(Level.FINER, LOG_MESSAGE, new Object[]{
                 req.getPathInfo(),
                 f.getSignature(),
@@ -58,7 +58,7 @@ public boolean onDoActionTrigger(Function f, StaplerRequest req, StaplerResponse
     }
 
     @Override
-    public boolean onGetterTrigger(Function f, StaplerRequest req, StaplerResponse rsp, Object node, String expression) {
+    public boolean onGetterTrigger(Function f, StaplerRequest2 req, StaplerResponse2 rsp, Object node, String expression) {
         LOGGER.log(Level.FINER, LOG_MESSAGE, new Object[]{
                 req.getPathInfo(),
                 f.getSignature(),
@@ -67,7 +67,7 @@ public boolean onGetterTrigger(Function f, StaplerRequest req, StaplerResponse r
     }
 
     @Override
-    public boolean onFieldTrigger(FieldRef f, StaplerRequest req, StaplerResponse staplerResponse, Object node, String expression) {
+    public boolean onFieldTrigger(FieldRef f, StaplerRequest2 req, StaplerResponse2 staplerResponse, Object node, String expression) {
         LOGGER.log(Level.FINER, LOG_MESSAGE, new Object[]{
                 req.getPathInfo(),
                 f.getSignature(),
@@ -76,7 +76,7 @@ public boolean onFieldTrigger(FieldRef f, StaplerRequest req, StaplerResponse st
     }
 
     @Override
-    public boolean onDispatchTrigger(StaplerRequest req, StaplerResponse rsp, Object node, String viewName) {
+    public boolean onDispatchTrigger(StaplerRequest2 req, StaplerResponse2 rsp, Object node, String viewName) {
         LOGGER.finer(() -> "New Stapler dispatch rules result in the URL \"" + req.getPathInfo() + "\" no longer being allowed. " +
                 "If you consider it safe to use, add the following to the whitelist: \"" + node.getClass().getName() + " " + viewName + "\". " +
                 "Learn more: https://www.jenkins.io/redirect/stapler-facet-restrictions");
diff --git a/core/src/main/java/jenkins/security/stapler/StaticRoutingDecisionProvider.java b/core/src/main/java/jenkins/security/stapler/StaticRoutingDecisionProvider.java
index abc61baf042b..5706504bd8f5 100644
--- a/core/src/main/java/jenkins/security/stapler/StaticRoutingDecisionProvider.java
+++ b/core/src/main/java/jenkins/security/stapler/StaticRoutingDecisionProvider.java
@@ -123,7 +123,7 @@ synchronized void resetAndSave() {
 
     private void resetMetaClassCache() {
         // to allow the change to be effective, i.e. rebuild the MetaClass using the new whitelist
-        WebApp.get(Jenkins.get().servletContext).clearMetaClassCache();
+        WebApp.get(Jenkins.get().getServletContext()).clearMetaClassCache();
     }
 
     private synchronized void reloadFromDefault() {
diff --git a/core/src/main/java/jenkins/security/stapler/WebMethodConstants.java b/core/src/main/java/jenkins/security/stapler/WebMethodConstants.java
index 90e14912005d..3227945cb293 100644
--- a/core/src/main/java/jenkins/security/stapler/WebMethodConstants.java
+++ b/core/src/main/java/jenkins/security/stapler/WebMethodConstants.java
@@ -24,20 +24,22 @@
 
 package jenkins.security.stapler;
 
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.lang.annotation.Annotation;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.AncestorInPath;
 import org.kohsuke.stapler.Header;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.bind.JavaScriptMethod;
 import org.kohsuke.stapler.json.JsonBody;
@@ -49,10 +51,14 @@ final class WebMethodConstants {
      * If a method has at least one of those parameters, it is considered as an implicit web method
      */
     private static final List<Class<?>> WEB_METHOD_PARAMETERS = List.of(
+            StaplerRequest2.class,
             StaplerRequest.class,
             HttpServletRequest.class,
+            javax.servlet.http.HttpServletRequest.class,
+            StaplerResponse2.class,
             StaplerResponse.class,
-            HttpServletResponse.class
+            HttpServletResponse.class,
+            javax.servlet.http.HttpServletResponse.class
     );
 
     static final Set<String> WEB_METHOD_PARAMETERS_NAMES = Collections.unmodifiableSet(
diff --git a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java
index 9dac60c0500c..dd68f02376f4 100644
--- a/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java
+++ b/core/src/main/java/jenkins/slaves/EncryptedSlaveAgentJnlpFile.java
@@ -5,6 +5,11 @@
 import hudson.security.Permission;
 import hudson.slaves.SlaveComputer;
 import hudson.util.Secret;
+import jakarta.servlet.RequestDispatcher;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
+import jakarta.servlet.http.HttpServletResponseWrapper;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
@@ -17,15 +22,10 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import javax.crypto.spec.SecretKeySpec;
-import javax.servlet.RequestDispatcher;
-import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
-import javax.servlet.http.HttpServletResponseWrapper;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.ResponseImpl;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Serves the JNLP file.
@@ -70,11 +70,11 @@ public EncryptedSlaveAgentJnlpFile(AccessControlled it, String viewName, String
     }
 
     @Override
-    public void generateResponse(StaplerRequest req, final StaplerResponse res, Object node) throws IOException, ServletException {
+    public void generateResponse(StaplerRequest2 req, final StaplerResponse2 res, Object node) throws IOException, ServletException {
         RequestDispatcher view = req.getView(it, viewName);
         if ("true".equals(req.getParameter("encrypt"))) {
             final CapturingServletOutputStream csos = new CapturingServletOutputStream();
-            StaplerResponse temp = new ResponseImpl(req.getStapler(), new HttpServletResponseWrapper(res) {
+            StaplerResponse2 temp = new ResponseImpl(req.getStapler(), new HttpServletResponseWrapper(res) {
                 @Override public ServletOutputStream getOutputStream() {
                     return csos;
                 }
diff --git a/core/src/main/java/jenkins/tasks/filters/EnvVarsFilterGlobalConfiguration.java b/core/src/main/java/jenkins/tasks/filters/EnvVarsFilterGlobalConfiguration.java
index 9e2258c5abed..230b1a700115 100644
--- a/core/src/main/java/jenkins/tasks/filters/EnvVarsFilterGlobalConfiguration.java
+++ b/core/src/main/java/jenkins/tasks/filters/EnvVarsFilterGlobalConfiguration.java
@@ -37,7 +37,7 @@
 import org.jenkinsci.Symbol;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.Beta;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Configuration of the filter rules that are applied globally,
@@ -75,7 +75,7 @@ public GlobalConfigurationCategory getCategory() {
     }
 
     @Override
-    public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
+    public boolean configure(StaplerRequest2 req, JSONObject json) throws FormException {
         try {
             activatedGlobalRules.rebuildHetero(req, json, getAllGlobalRules(), "rules");
         } catch (IOException e) {
diff --git a/core/src/main/java/jenkins/telemetry/impl/StaplerDispatches.java b/core/src/main/java/jenkins/telemetry/impl/StaplerDispatches.java
index 66078caa3d33..5cf16e0b0e49 100644
--- a/core/src/main/java/jenkins/telemetry/impl/StaplerDispatches.java
+++ b/core/src/main/java/jenkins/telemetry/impl/StaplerDispatches.java
@@ -38,7 +38,7 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.EvaluationTrace;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Telemetry implementation gathering information about Stapler dispatch routes.
@@ -86,7 +86,7 @@ private Object buildDispatches() {
     public static class StaplerTrace extends EvaluationTrace.ApplicationTracer {
 
         @Override
-        protected void record(StaplerRequest staplerRequest, String s) {
+        protected void record(StaplerRequest2 staplerRequest, String s) {
             if (Telemetry.isDisabled()) {
                 // do not collect traces while usage statistics are disabled
                 return;
diff --git a/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java b/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java
index 8bf24d1b01a9..0a03b0fe653c 100644
--- a/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java
+++ b/core/src/main/java/jenkins/telemetry/impl/UserLanguages.java
@@ -26,6 +26,9 @@
 
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.Extension;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.time.LocalDate;
 import java.util.Map;
@@ -33,9 +36,6 @@
 import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.telemetry.Telemetry;
 import jenkins.util.HttpServletFilter;
 import net.sf.json.JSONObject;
diff --git a/core/src/main/java/jenkins/tools/GlobalToolConfiguration.java b/core/src/main/java/jenkins/tools/GlobalToolConfiguration.java
index bcca8506c5dd..47208f942958 100644
--- a/core/src/main/java/jenkins/tools/GlobalToolConfiguration.java
+++ b/core/src/main/java/jenkins/tools/GlobalToolConfiguration.java
@@ -32,17 +32,17 @@
 import hudson.model.ManagementLink;
 import hudson.security.Permission;
 import hudson.util.FormApply;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.function.Predicate;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 @Extension(ordinal = Integer.MAX_VALUE - 220)
@@ -81,13 +81,13 @@ public Category getCategory() {
     }
 
     @POST
-    public synchronized void doConfigure(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException, Descriptor.FormException {
+    public synchronized void doConfigure(StaplerRequest2 req, StaplerResponse2 rsp) throws IOException, ServletException, Descriptor.FormException {
         boolean result = configure(req, req.getSubmittedForm());
         LOGGER.log(Level.FINE, "tools saved: " + result);
         FormApply.success(req.getContextPath() + "/manage").generateResponse(req, rsp, null);
     }
 
-    private boolean configure(StaplerRequest req, JSONObject json) throws Descriptor.FormException, IOException {
+    private boolean configure(StaplerRequest2 req, JSONObject json) throws Descriptor.FormException, IOException {
         Jenkins j = Jenkins.get();
         j.checkPermission(Jenkins.ADMINISTER);
 
@@ -100,7 +100,7 @@ private boolean configure(StaplerRequest req, JSONObject json) throws Descriptor
         return result;
     }
 
-    private boolean configureDescriptor(StaplerRequest req, JSONObject json, Descriptor<?> d) throws Descriptor.FormException {
+    private boolean configureDescriptor(StaplerRequest2 req, JSONObject json, Descriptor<?> d) throws Descriptor.FormException {
         String name = d.getJsonSafeClassName();
         JSONObject js = json.has(name) ? json.getJSONObject(name) : new JSONObject(); // if it doesn't have the property, the method returns invalid null object.
         json.putAll(js);
diff --git a/core/src/main/java/jenkins/util/FullDuplexHttpService.java b/core/src/main/java/jenkins/util/FullDuplexHttpService.java
index 01f79b029125..28b9334204e4 100644
--- a/core/src/main/java/jenkins/util/FullDuplexHttpService.java
+++ b/core/src/main/java/jenkins/util/FullDuplexHttpService.java
@@ -30,6 +30,8 @@
 import hudson.security.csrf.CrumbExclusion;
 import hudson.util.ChunkedInputStream;
 import hudson.util.ChunkedOutputStream;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -38,13 +40,11 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Server-side counterpart to {@link FullDuplexHttpStream}.
@@ -86,7 +86,7 @@ protected FullDuplexHttpService(UUID uuid) {
      * <p>
      * If this connection is lost, we'll abort the channel.
      */
-    public synchronized void download(StaplerRequest req, StaplerResponse rsp) throws InterruptedException, IOException {
+    public synchronized void download(StaplerRequest2 req, StaplerResponse2 rsp) throws InterruptedException, IOException {
         rsp.setStatus(HttpServletResponse.SC_OK);
 
         // server->client channel.
@@ -129,7 +129,7 @@ public synchronized void download(StaplerRequest req, StaplerResponse rsp) throw
     /**
      * This is where we receive inputs from the client.
      */
-    public synchronized void upload(StaplerRequest req, StaplerResponse rsp) throws InterruptedException, IOException {
+    public synchronized void upload(StaplerRequest2 req, StaplerResponse2 rsp) throws InterruptedException, IOException {
         rsp.setStatus(HttpServletResponse.SC_OK);
         InputStream in = req.getInputStream();
         if (DIY_CHUNKING) {
@@ -163,7 +163,7 @@ protected Response(Map<UUID, FullDuplexHttpService> services) {
         }
 
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             try {
                 // do not require any permission to establish a CLI connection
                 // the actual authentication for the connecting Channel is done by CLICommand
@@ -198,7 +198,7 @@ public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object nod
             }
         }
 
-        protected abstract FullDuplexHttpService createService(StaplerRequest req, UUID uuid) throws IOException, InterruptedException;
+        protected abstract FullDuplexHttpService createService(StaplerRequest2 req, UUID uuid) throws IOException, InterruptedException;
 
     }
 
diff --git a/core/src/main/java/jenkins/util/HttpServletFilter.java b/core/src/main/java/jenkins/util/HttpServletFilter.java
index b83b37d1174d..da00b32b2908 100644
--- a/core/src/main/java/jenkins/util/HttpServletFilter.java
+++ b/core/src/main/java/jenkins/util/HttpServletFilter.java
@@ -29,17 +29,18 @@
 import hudson.init.Initializer;
 import hudson.security.csrf.CrumbExclusion;
 import hudson.util.PluginServletFilter;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
-import javax.servlet.Filter;
-import javax.servlet.FilterChain;
-import javax.servlet.FilterConfig;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.DoNotUse;
+import org.kohsuke.stapler.CompatibleFilter;
 
 /**
  * More convenient and declarative way to use {@link PluginServletFilter}.
@@ -63,7 +64,7 @@ public interface HttpServletFilter extends ExtensionPoint {
     @Restricted(DoNotUse.class)
     @Initializer
     static void register() throws ServletException {
-        PluginServletFilter.addFilter(new Filter() {
+        PluginServletFilter.addFilter(new CompatibleFilter() {
             @Override
             public void doFilter(ServletRequest req, ServletResponse rsp, FilterChain chain) throws IOException, ServletException {
                 if (req instanceof HttpServletRequest && rsp instanceof HttpServletResponse) {
diff --git a/core/src/main/java/jenkins/util/HttpSessionListener.java b/core/src/main/java/jenkins/util/HttpSessionListener.java
index 7f3649fd2381..85ff806ac6e6 100644
--- a/core/src/main/java/jenkins/util/HttpSessionListener.java
+++ b/core/src/main/java/jenkins/util/HttpSessionListener.java
@@ -28,11 +28,13 @@
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import hudson.ExtensionList;
 import hudson.ExtensionPoint;
-import javax.servlet.http.HttpSession;
-import javax.servlet.http.HttpSessionEvent;
+import hudson.Util;
+import io.jenkins.servlet.http.HttpSessionEventWrapper;
+import jakarta.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSessionEvent;
 
 /**
- * {@link javax.servlet.http.HttpSessionListener} {@link ExtensionPoint} for Jenkins.
+ * {@link jakarta.servlet.http.HttpSessionListener} {@link ExtensionPoint} for Jenkins.
  * <p>
  * Allows plugins to listen to {@link HttpSession} lifecycle events.
  *
@@ -40,7 +42,7 @@
  * @since 2.2
  */
 @SuppressFBWarnings(value = "NM_SAME_SIMPLE_NAME_AS_INTERFACE", justification = "Should shadow HttpSessionListener")
-public abstract class HttpSessionListener implements ExtensionPoint, javax.servlet.http.HttpSessionListener {
+public abstract class HttpSessionListener implements ExtensionPoint, jakarta.servlet.http.HttpSessionListener, javax.servlet.http.HttpSessionListener {
 
     /**
      * Get all of the {@link HttpSessionListener} implementations.
@@ -52,9 +54,37 @@ public static ExtensionList<HttpSessionListener> all() {
 
     @Override
     public void sessionCreated(HttpSessionEvent httpSessionEvent) {
+        if (Util.isOverridden(HttpSessionListener.class, getClass(), "sessionCreated", javax.servlet.http.HttpSessionEvent.class)) {
+            sessionCreated(HttpSessionEventWrapper.fromJakartaHttpSessionEvent(httpSessionEvent));
+        }
     }
 
     @Override
     public void sessionDestroyed(HttpSessionEvent httpSessionEvent) {
+        if (Util.isOverridden(HttpSessionListener.class, getClass(), "sessionCreated", javax.servlet.http.HttpSessionEvent.class)) {
+            sessionCreated(HttpSessionEventWrapper.fromJakartaHttpSessionEvent(httpSessionEvent));
+        }
+    }
+
+    /**
+     * @deprecated use {@link #sessionCreated(HttpSessionEvent)}
+     */
+    @Deprecated
+    @Override
+    public void sessionCreated(javax.servlet.http.HttpSessionEvent httpSessionEvent) {
+        if (Util.isOverridden(HttpSessionListener.class, getClass(), "sessionCreated", HttpSessionEvent.class)) {
+            sessionCreated(HttpSessionEventWrapper.toJakartaHttpSessionEvent(httpSessionEvent));
+        }
+    }
+
+    /**
+     * @deprecated use {@link #sessionDestroyed(HttpSessionEvent)}
+     */
+    @Deprecated
+    @Override
+    public void sessionDestroyed(javax.servlet.http.HttpSessionEvent httpSessionEvent) {
+        if (Util.isOverridden(HttpSessionListener.class, getClass(), "sessionDestroyed", HttpSessionEvent.class)) {
+            sessionDestroyed(HttpSessionEventWrapper.toJakartaHttpSessionEvent(httpSessionEvent));
+        }
     }
 }
diff --git a/core/src/main/java/jenkins/util/JSONSignatureValidator.java b/core/src/main/java/jenkins/util/JSONSignatureValidator.java
index 3cc10ebd4038..e6f5429f43bc 100644
--- a/core/src/main/java/jenkins/util/JSONSignatureValidator.java
+++ b/core/src/main/java/jenkins/util/JSONSignatureValidator.java
@@ -252,12 +252,12 @@ protected Set<TrustAnchor> loadTrustAnchors(CertificateFactory cf) throws IOExce
         // which isn't useful at all
         Set<TrustAnchor> anchors = new HashSet<>(); // CertificateUtil.getDefaultRootCAs();
         Jenkins j = Jenkins.get();
-        for (String cert : j.servletContext.getResourcePaths("/WEB-INF/update-center-rootCAs")) {
+        for (String cert : j.getServletContext().getResourcePaths("/WEB-INF/update-center-rootCAs")) {
             if (cert.endsWith("/") || cert.endsWith(".txt"))  {
                 continue;       // skip directories also any text files that are meant to be documentation
             }
             Certificate certificate;
-            try (InputStream in = j.servletContext.getResourceAsStream(cert)) {
+            try (InputStream in = j.getServletContext().getResourceAsStream(cert)) {
                 if (in == null) continue; // our test for paths ending in / should prevent this from happening
                 certificate = cf.generateCertificate(in);
                 if (certificate instanceof X509Certificate) {
diff --git a/core/src/main/java/jenkins/util/JenkinsJVM.java b/core/src/main/java/jenkins/util/JenkinsJVM.java
index fafe1223a389..c13389493f41 100644
--- a/core/src/main/java/jenkins/util/JenkinsJVM.java
+++ b/core/src/main/java/jenkins/util/JenkinsJVM.java
@@ -1,7 +1,7 @@
 package jenkins.util;
 
 import hudson.WebAppMain;
-import javax.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextEvent;
 import jenkins.model.Jenkins;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
diff --git a/core/src/main/java/jenkins/util/ProgressiveRendering.java b/core/src/main/java/jenkins/util/ProgressiveRendering.java
index 460ac3afd82b..9dc2102b5bcc 100644
--- a/core/src/main/java/jenkins/util/ProgressiveRendering.java
+++ b/core/src/main/java/jenkins/util/ProgressiveRendering.java
@@ -26,6 +26,7 @@
 
 import edu.umd.cs.findbugs.annotations.NonNull;
 import hudson.model.AbstractItem;
+import jakarta.servlet.http.HttpServletRequest;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
@@ -39,7 +40,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.http.HttpServletRequest;
 import net.sf.json.JSON;
 import net.sf.json.JSONObject;
 import org.kohsuke.stapler.Ancestor;
@@ -103,7 +103,7 @@ protected ProgressiveRendering() {
      * For internal use.
      */
     @JavaScriptMethod public final void start() {
-        Ancestor ancestor = Stapler.getCurrentRequest().findAncestor(BoundObjectTable.class);
+        Ancestor ancestor = Stapler.getCurrentRequest2().findAncestor(BoundObjectTable.class);
         if (ancestor == null) {
             throw new IllegalStateException("no BoundObjectTable");
         }
@@ -159,7 +159,7 @@ private void release() {
      */
     @java.lang.SuppressWarnings({"rawtypes", "unchecked"}) // public RequestImpl ctor requires List<AncestorImpl> yet AncestorImpl is not public! API design flaw
     private static RequestImpl createMockRequest() {
-        RequestImpl currentRequest = (RequestImpl) Stapler.getCurrentRequest();
+        RequestImpl currentRequest = (RequestImpl) Stapler.getCurrentRequest2();
         HttpServletRequest original = (HttpServletRequest) currentRequest.getRequest();
         final Map<String, Object> getters = new HashMap<>();
         for (Method method : HttpServletRequest.class.getMethods()) {
@@ -205,7 +205,7 @@ private static void setCurrentRequest(RequestImpl request) {
     /**
      * Actually do the work.
      * <p>The security context will be that in effect when the web request was made.
-     * {@link Stapler#getCurrentRequest} will also be similar to that in effect when the web request was made;
+     * {@link Stapler#getCurrentRequest2} will also be similar to that in effect when the web request was made;
      * at least, {@link Ancestor}s and basic request properties (URI, locale, and so on) will be available.
      * @throws Exception whenever you like; the progress bar will indicate that an error occurred but details go to the log only
      */
diff --git a/core/src/main/java/jenkins/util/ScriptListener.java b/core/src/main/java/jenkins/util/ScriptListener.java
index b07603c17f2a..f75596b8c85d 100644
--- a/core/src/main/java/jenkins/util/ScriptListener.java
+++ b/core/src/main/java/jenkins/util/ScriptListener.java
@@ -36,7 +36,7 @@
 import java.nio.charset.Charset;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * A listener to track in-process script use.
@@ -44,7 +44,7 @@
  * <p>Note that (unsandboxed) script execution can easily result in logging configuration being changed, so if you rely
  * on complete logging of scripting actions, make sure to set up logging to remote systems.</p>
  *
- * @see jenkins.model.Jenkins#_doScript(StaplerRequest, org.kohsuke.stapler.StaplerResponse, javax.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL)
+ * @see jenkins.model.Jenkins#_doScript(StaplerRequest2, org.kohsuke.stapler.StaplerResponse2, jakarta.servlet.RequestDispatcher, hudson.remoting.VirtualChannel, hudson.security.ACL)
  * @see hudson.cli.GroovyCommand
  * @see hudson.cli.GroovyshCommand
  * @see jenkins.util.groovy.GroovyHookScript
diff --git a/core/src/main/java/jenkins/util/SystemProperties.java b/core/src/main/java/jenkins/util/SystemProperties.java
index d32a91e2db79..e3818b69f921 100644
--- a/core/src/main/java/jenkins/util/SystemProperties.java
+++ b/core/src/main/java/jenkins/util/SystemProperties.java
@@ -34,6 +34,9 @@
 import hudson.model.TaskListener;
 import hudson.remoting.Channel;
 import hudson.slaves.ComputerListener;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletContextEvent;
+import jakarta.servlet.ServletContextListener;
 import java.io.IOException;
 import java.util.Collections;
 import java.util.HashMap;
@@ -42,9 +45,6 @@
 import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
-import javax.servlet.ServletContextListener;
 import jenkins.security.MasterToSlaveCallable;
 import jenkins.util.io.OnMaster;
 import org.kohsuke.accmod.Restricted;
diff --git a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java
index eeb816f31ffd..1539d75715c5 100644
--- a/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java
+++ b/core/src/main/java/jenkins/util/groovy/GroovyHookScript.java
@@ -8,6 +8,8 @@
 import groovy.lang.GroovyCodeSource;
 import groovy.lang.GroovyShell;
 import hudson.model.User;
+import io.jenkins.servlet.ServletContextWrapper;
+import jakarta.servlet.ServletContext;
 import java.io.File;
 import java.io.IOException;
 import java.net.URL;
@@ -15,7 +17,6 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.logging.Logger;
-import javax.servlet.ServletContext;
 import jenkins.model.Jenkins;
 import jenkins.util.ScriptListener;
 import jenkins.util.SystemProperties;
@@ -55,7 +56,7 @@ public GroovyHookScript(String hook) {
     }
 
     private GroovyHookScript(String hook, Jenkins j) {
-        this(hook, j.servletContext, j.getRootDir(), j.getPluginManager().uberClassLoader);
+        this(hook, j.getServletContext(), j.getRootDir(), j.getPluginManager().uberClassLoader);
     }
 
     public GroovyHookScript(String hook, @NonNull ServletContext servletContext, @NonNull File jenkinsHome, @NonNull ClassLoader loader) {
@@ -65,6 +66,14 @@ public GroovyHookScript(String hook, @NonNull ServletContext servletContext, @No
         this.loader = loader;
     }
 
+    /**
+     * @deprecated use {@link #GroovyHookScript(String, ServletContext, File, ClassLoader)}
+     */
+    @Deprecated
+    public GroovyHookScript(String hook, @NonNull javax.servlet.ServletContext servletContext, @NonNull File jenkinsHome, @NonNull ClassLoader loader) {
+        this(hook, ServletContextWrapper.toJakartaServletContext(servletContext), jenkinsHome, loader);
+    }
+
     public GroovyHookScript bind(String name, Object o) {
         bindings.setProperty(name, o);
         return this;
diff --git a/core/src/main/java/jenkins/websocket/WebSockets.java b/core/src/main/java/jenkins/websocket/WebSockets.java
index 0f275864c23f..5e0152381e3e 100644
--- a/core/src/main/java/jenkins/websocket/WebSockets.java
+++ b/core/src/main/java/jenkins/websocket/WebSockets.java
@@ -24,6 +24,9 @@
 
 package jenkins.websocket;
 
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.nio.channels.ClosedChannelException;
 import java.util.Iterator;
@@ -31,13 +34,11 @@
 import java.util.ServiceLoader;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.Beta;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * Support for serving WebSocket responses.
@@ -65,11 +66,16 @@ private static Provider findProvider() {
     // TODO ability to handle subprotocols?
 
     public static HttpResponse upgrade(WebSocketSession session) {
-        return (req, rsp, node) -> upgradeResponse(session, req, rsp);
+        return new HttpResponse() {
+            @Override
+            public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
+                upgradeResponse(session, req, rsp);
+            }
+        };
     }
 
     /**
-     * Variant of {@link #upgrade} that does not presume a {@link StaplerRequest}.
+     * Variant of {@link #upgrade} that does not presume a {@link StaplerRequest2}.
      * @since 2.446
      */
     public static void upgradeResponse(WebSocketSession session, HttpServletRequest req, HttpServletResponse rsp) throws IOException, ServletException {
diff --git a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServices.java b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServices.java
index 853905eb1c6a..379dd1b4d15e 100644
--- a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServices.java
+++ b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServices.java
@@ -24,8 +24,8 @@
 
 package org.acegisecurity.ui.rememberme;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import org.acegisecurity.Authentication;
 
 /**
diff --git a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServicesSpringImpl.java b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServicesSpringImpl.java
index 5a0cd0d63d86..5dca4372020f 100644
--- a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServicesSpringImpl.java
+++ b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeServicesSpringImpl.java
@@ -24,8 +24,8 @@
 
 package org.acegisecurity.ui.rememberme;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import org.acegisecurity.Authentication;
 
 final class RememberMeServicesSpringImpl implements org.springframework.security.web.authentication.RememberMeServices {
diff --git a/core/src/main/resources/jenkins/model/Jenkins/_404.jelly b/core/src/main/resources/jenkins/model/Jenkins/_404.jelly
index 4605b5926760..7230e4f31acc 100644
--- a/core/src/main/resources/jenkins/model/Jenkins/_404.jelly
+++ b/core/src/main/resources/jenkins/model/Jenkins/_404.jelly
@@ -29,8 +29,8 @@ THE SOFTWARE.
       Generally kept very similar to 'oops.jelly'.
     -->
     <st:statusCode value="${response.getStatus()}" />
-    ${request.session.setAttribute('from', request.getAttribute('javax.servlet.error.request_uri'))}
-    <l:layout title="${%title(javax.servlet.error.message?:'Not Found')}" type="one-column">
+    ${request.session.setAttribute('from', request.getAttribute('jakarta.servlet.error.request_uri'))}
+    <l:layout title="${%title(jakarta.servlet.error.message?:'Not Found')}" type="one-column">
         <l:header />
         <l:main-panel>
             <h1 style="text-align: center">
@@ -38,7 +38,7 @@ THE SOFTWARE.
                 <span style="font-size:50px"><st:nbsp/>${%Oops!}</span>
             </h1>
             <div id="error-description" style="text-align: center">
-                <h2>${%title(javax.servlet.error.message?:'Not Found')}</h2>
+                <h2>${%title(jakarta.servlet.error.message?:'Not Found')}</h2>
                 <j:if test="${!request.getAttribute('jenkins.security.ResourceDomainRootAction.error')}">
 	                <p>
 	                    <j:choose>
diff --git a/core/src/main/resources/jenkins/model/Jenkins/_404_simple.jelly b/core/src/main/resources/jenkins/model/Jenkins/_404_simple.jelly
index c6a876bb2955..e59083103a55 100644
--- a/core/src/main/resources/jenkins/model/Jenkins/_404_simple.jelly
+++ b/core/src/main/resources/jenkins/model/Jenkins/_404_simple.jelly
@@ -39,7 +39,7 @@ THE SOFTWARE.
         <st:statusCode value="${response.getStatus()}" />
         <html>
             <head>
-                <title>${%title(javax.servlet.error.message?:'Not Found')}</title>
+                <title>${%title(jakarta.servlet.error.message?:'Not Found')}</title>
                 <link rel="icon" href="${resURL}/favicon.svg" type="image/svg+xml" />
                 <link rel="alternate icon" href="${resURL}/favicon.ico" sizes="any" />
                 <!-- TODO Determine need for these -->
@@ -52,7 +52,7 @@ THE SOFTWARE.
                     <span style="font-size:50px"><st:nbsp/>${%Oops!}</span>
                 </h1>
                 <div style="text-align: center">
-                    <h2>${%title(javax.servlet.error.message?:'Not Found')}</h2>
+                    <h2>${%title(jakarta.servlet.error.message?:'Not Found')}</h2>
                     <a href="${h.inferHudsonURL(request)}">${%Back to Jenkins}</a>
                 </div>
             </body>
diff --git a/core/src/main/resources/jenkins/model/Jenkins/oops.jelly b/core/src/main/resources/jenkins/model/Jenkins/oops.jelly
index 28238c660253..436b4a8fc0a6 100644
--- a/core/src/main/resources/jenkins/model/Jenkins/oops.jelly
+++ b/core/src/main/resources/jenkins/model/Jenkins/oops.jelly
@@ -41,7 +41,7 @@ THE SOFTWARE.
       <j:if test="${app.shouldShowStackTrace()}">
         <p>${%checkJIRA} ${%vote} ${%pleaseReport} ${%stackTracePlease} ${%checkML}</p>
         <h2>${%Stack trace}</h2>
-        <pre style="margin:2em; clear:both">${h.printThrowable(request.getAttribute('javax.servlet.error.exception'))}</pre>
+        <pre style="margin:2em; clear:both">${h.printThrowable(request.getAttribute('jakarta.servlet.error.exception'))}</pre>
       </j:if>
     </l:main-panel>
   </l:layout>
diff --git a/core/src/test/java/hudson/FunctionsTest.java b/core/src/test/java/hudson/FunctionsTest.java
index 95d5def0bbda..5a0df319bfcc 100644
--- a/core/src/test/java/hudson/FunctionsTest.java
+++ b/core/src/test/java/hudson/FunctionsTest.java
@@ -61,7 +61,7 @@
 import org.jvnet.hudson.test.Issue;
 import org.kohsuke.stapler.Ancestor;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.mockito.MockedStatic;
 
 public class FunctionsTest {
@@ -96,14 +96,14 @@ public void testGetActionUrl_absoluteUriWithoutAuthority() {
     @Test
     public void testGetActionUrl_absolutePath() {
         String contextPath = "/jenkins";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         String[] paths = {
             "/",
             "/foo/bar",
         };
 
         try (MockedStatic<Stapler> mocked = mockStatic(Stapler.class)) {
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             for (String path : paths) {
                 String result = Functions.getActionUrl(null, createMockAction(path));
                 assertEquals(contextPath + path, result);
@@ -115,14 +115,14 @@ public void testGetActionUrl_absolutePath() {
     public void testGetActionUrl_relativePath() {
         String contextPath = "/jenkins";
         String itUrl = "iturl/";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         String[] paths = {
             "foo/bar",
             "./foo/bar",
             "../foo/bar",
         };
         try (MockedStatic<Stapler> mocked = mockStatic(Stapler.class)) {
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             for (String path : paths) {
                 String result = Functions.getActionUrl(itUrl, createMockAction(path));
                 assertEquals(contextPath + "/" + itUrl + path, result);
@@ -133,14 +133,14 @@ public void testGetActionUrl_relativePath() {
     @Test
     public void testGetRelativeLinkTo_JobContainedInView() {
         String contextPath = "/jenkins";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         try (
                 MockedStatic<Stapler> mocked = mockStatic(Stapler.class);
                 MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)
         ) {
             Jenkins j = createMockJenkins(mockedJenkins);
             ItemGroup parent = j;
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             View view = mock(View.class);
             when(view.getOwner()).thenReturn(j);
             when(j.getItemGroup()).thenReturn(j);
@@ -155,14 +155,14 @@ public void testGetRelativeLinkTo_JobContainedInView() {
     @Test
     public void testGetRelativeLinkTo_JobFromComputer() {
         String contextPath = "/jenkins";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         try (
                 MockedStatic<Stapler> mocked = mockStatic(Stapler.class);
                 MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)
         ) {
             Jenkins j = createMockJenkins(mockedJenkins);
             ItemGroup parent = j;
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             Computer computer = mock(Computer.class);
             createMockAncestors(req, createAncestor(computer, "."), createAncestor(j, "../.."));
             TopLevelItem i = createMockItem(parent, "job/i/");
@@ -175,14 +175,14 @@ public void testGetRelativeLinkTo_JobFromComputer() {
     @Test
     public void testGetRelativeLinkTo_JobNotContainedInView() {
         String contextPath = "/jenkins";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         try (
                 MockedStatic<Stapler> mocked = mockStatic(Stapler.class);
                 MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)
         ) {
             Jenkins j = createMockJenkins(mockedJenkins);
             ItemGroup parent = j;
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             View view = mock(View.class);
             when(view.getOwner().getItemGroup()).thenReturn(parent);
             createMockAncestors(req, createAncestor(j, "../.."), createAncestor(view, "."));
@@ -198,7 +198,7 @@ private interface TopLevelItemAndItemGroup<T extends TopLevelItem> extends TopLe
     @Test
     public void testGetRelativeLinkTo_JobContainedInViewWithinItemGroup() {
         String contextPath = "/jenkins";
-        StaplerRequest req = createMockRequest(contextPath);
+        StaplerRequest2 req = createMockRequest(contextPath);
         try (
                 MockedStatic<Stapler> mocked = mockStatic(Stapler.class);
                 MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)
@@ -206,7 +206,7 @@ public void testGetRelativeLinkTo_JobContainedInViewWithinItemGroup() {
             Jenkins j = createMockJenkins(mockedJenkins);
             TopLevelItemAndItemGroup parent = mock(TopLevelItemAndItemGroup.class);
             when(parent.getShortUrl()).thenReturn("parent/");
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             View view = mock(View.class);
             when(view.getOwner()).thenReturn(parent);
             when(parent.getItemGroup()).thenReturn(parent);
@@ -220,13 +220,13 @@ public void testGetRelativeLinkTo_JobContainedInViewWithinItemGroup() {
 
     @Issue("JENKINS-17713")
     @Test public void getRelativeLinkTo_MavenModules() {
-        StaplerRequest req = createMockRequest("/jenkins");
+        StaplerRequest2 req = createMockRequest("/jenkins");
         try (
                 MockedStatic<Stapler> mocked = mockStatic(Stapler.class);
                 MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)
         ) {
             Jenkins j = createMockJenkins(mockedJenkins);
-            mocked.when(Stapler::getCurrentRequest).thenReturn(req);
+            mocked.when(Stapler::getCurrentRequest2).thenReturn(req);
             TopLevelItemAndItemGroup ms = mock(TopLevelItemAndItemGroup.class);
             when(ms.getShortUrl()).thenReturn("job/ms/");
             // TODO "." (in second ancestor) is what Stapler currently fails to do. Could edit test to use ".." but set a different request path?
@@ -266,7 +266,7 @@ public void testGetRelativeDisplayNameInsideItemGroup() {
         assertEquals(".. » top", Functions.getRelativeDisplayNameFrom(i2, ig));
     }
 
-    private void createMockAncestors(StaplerRequest req, Ancestor... ancestors) {
+    private void createMockAncestors(StaplerRequest2 req, Ancestor... ancestors) {
         List<Ancestor> ancestorsList = Arrays.asList(ancestors);
         when(req.getAncestors()).thenReturn(ancestorsList);
     }
@@ -307,8 +307,8 @@ private static Action createMockAction(String uri) {
         return action;
     }
 
-    private static StaplerRequest createMockRequest(String contextPath) {
-        StaplerRequest req = mock(StaplerRequest.class);
+    private static StaplerRequest2 createMockRequest(String contextPath) {
+        StaplerRequest2 req = mock(StaplerRequest2.class);
         when(req.getContextPath()).thenReturn(contextPath);
         return req;
     }
diff --git a/core/src/test/java/hudson/GetLocaleStaticHelpUrlTest.java b/core/src/test/java/hudson/GetLocaleStaticHelpUrlTest.java
index a61fc0d54656..f139475b1013 100644
--- a/core/src/test/java/hudson/GetLocaleStaticHelpUrlTest.java
+++ b/core/src/test/java/hudson/GetLocaleStaticHelpUrlTest.java
@@ -37,7 +37,7 @@
 import java.util.Locale;
 import org.junit.jupiter.api.Test;
 import org.jvnet.hudson.test.Issue;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.lang.Klass;
 
 public class GetLocaleStaticHelpUrlTest {
@@ -45,7 +45,7 @@ public class GetLocaleStaticHelpUrlTest {
     @Test
     public void getStaticHelpUrlAcceptEnResDefault() {
         // Accept-Language: en
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.ENGLISH
         );
 
@@ -60,7 +60,7 @@ public void getStaticHelpUrlAcceptEnResDefault() {
     @Test
     public void getStaticHelpUrlAcceptDeResDeNoCountry() {
         // Accept-Language: de-DE,de;q=0.9,en;q=0.8
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.GERMANY,
                 Locale.GERMAN,
                 Locale.ENGLISH
@@ -78,7 +78,7 @@ public void getStaticHelpUrlAcceptDeResDeNoCountry() {
     @Test
     public void getStaticHelpUrlAcceptDeResDeCountry() {
         // Accept-Language: de-DE,de;q=0.9,en;q=0.8
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.GERMANY,
                 Locale.GERMAN,
                 Locale.ENGLISH
@@ -96,7 +96,7 @@ public void getStaticHelpUrlAcceptDeResDeCountry() {
     @Test
     public void getStaticHelpUrlAcceptDeResBoth() {
         // Accept-Language: de-DE,de;q=0.9,en;q=0.8
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.GERMANY,
                 Locale.GERMAN,
                 Locale.ENGLISH
@@ -115,7 +115,7 @@ public void getStaticHelpUrlAcceptDeResBoth() {
     @Test
     public void getStaticHelpUrlAcceptZhResDefault() {
         // Accept-Language: zh,zh-CN;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.CHINESE,
                 Locale.SIMPLIFIED_CHINESE,
                 Locale.ENGLISH,
@@ -134,7 +134,7 @@ public void getStaticHelpUrlAcceptZhResDefault() {
     @Test
     public void getStaticHelpUrlAcceptZhResZhCountry() {
         // Accept-Language: zh,zh-CN;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.CHINESE,
                 Locale.SIMPLIFIED_CHINESE,
                 Locale.ENGLISH,
@@ -154,7 +154,7 @@ public void getStaticHelpUrlAcceptZhResZhCountry() {
     @Test
     public void getStaticHelpUrlAcceptZhResBoth() {
         // Accept-Language: zh,zh-CN;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.CHINESE,
                 Locale.SIMPLIFIED_CHINESE,
                 Locale.ENGLISH,
@@ -174,7 +174,7 @@ public void getStaticHelpUrlAcceptZhResBoth() {
     @Test
     public void getStaticHelpUrlAcceptZhResMore() {
         // Accept-Language: zh,zh-CN;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.CHINESE,
                 Locale.SIMPLIFIED_CHINESE,
                 Locale.ENGLISH,
@@ -196,7 +196,7 @@ public void getStaticHelpUrlAcceptZhResMore() {
     @Test
     public void getStaticHelpUrlAcceptEnFirst() {
         // Accept-Language: en-US,en;q=0.9,de;q=0.8
-        StaplerRequest req = mockStaplerRequest(
+        StaplerRequest2 req = mockStaplerRequest2(
                 Locale.US,
                 Locale.ENGLISH,
                 Locale.GERMAN
@@ -210,8 +210,8 @@ public void getStaticHelpUrlAcceptEnFirst() {
         assertThatLocaleResourceIs(id, "help-id.html");
     }
 
-    private StaplerRequest mockStaplerRequest(Locale... localeArr) {
-        StaplerRequest req = mock(StaplerRequest.class);
+    private StaplerRequest2 mockStaplerRequest2(Locale... localeArr) {
+        StaplerRequest2 req = mock(StaplerRequest2.class);
         Enumeration<Locale> locales = Collections.enumeration(Arrays.asList(localeArr));
         when(req.getLocales()).thenReturn(locales);
         return req;
diff --git a/core/src/test/java/hudson/model/QueueTest.java b/core/src/test/java/hudson/model/QueueTest.java
index 1a338371ff41..9e3320124e89 100644
--- a/core/src/test/java/hudson/model/QueueTest.java
+++ b/core/src/test/java/hudson/model/QueueTest.java
@@ -3,16 +3,16 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.PrintWriter;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.jvnet.hudson.test.Issue;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
@@ -20,7 +20,7 @@
 public class QueueTest {
 
     @Mock
-    StaplerResponse resp;
+    StaplerResponse2 resp;
     @Mock
     Queue.Task task;
     @Mock
diff --git a/core/src/test/java/hudson/model/ViewTest.java b/core/src/test/java/hudson/model/ViewTest.java
index cd76ea6250e3..51b45ab6fb10 100644
--- a/core/src/test/java/hudson/model/ViewTest.java
+++ b/core/src/test/java/hudson/model/ViewTest.java
@@ -13,8 +13,8 @@
 import java.util.List;
 import org.junit.Test;
 import org.jvnet.hudson.test.Issue;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.mockito.Mockito;
 
 public class ViewTest {
@@ -186,11 +186,11 @@ public boolean contains(TopLevelItem item) {
         }
 
         @Override
-        protected void submit(StaplerRequest req) {
+        protected void submit(StaplerRequest2 req) {
         }
 
         @Override
-        public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) {
+        public Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) {
             return null;
         }
     }
diff --git a/core/src/test/java/hudson/util/FormValidationTest.java b/core/src/test/java/hudson/util/FormValidationTest.java
index 51deec680af7..a783665c5309 100644
--- a/core/src/test/java/hudson/util/FormValidationTest.java
+++ b/core/src/test/java/hudson/util/FormValidationTest.java
@@ -35,7 +35,6 @@
 import java.io.IOException;
 import java.net.URI;
 import java.util.Arrays;
-import javax.servlet.ServletException;
 import org.junit.Test;
 
 /**
@@ -122,10 +121,10 @@ public void formValidationException() {
     }
 
     @Test
-    public void testUrlCheck() throws IOException, ServletException {
+    public void testUrlCheck() throws IOException {
         FormValidation.URLCheck urlCheck = new FormValidation.URLCheck() {
             @Override
-            protected FormValidation check() throws ServletException, IOException {
+            protected FormValidation check() throws IOException {
                 String uri = "https://www.jenkins.io/";
                 try {
                     if (findText(open(URI.create(uri)), "Jenkins")) {
diff --git a/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java b/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java
index 620616a15081..51706cf18680 100644
--- a/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java
+++ b/core/src/test/java/jenkins/model/JenkinsGetRootUrlTest.java
@@ -36,7 +36,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.Issue;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.invocation.InvocationOnMock;
@@ -45,14 +45,14 @@
 public class JenkinsGetRootUrlTest {
 
     private Jenkins jenkins;
-    private StaplerRequest staplerRequest;
+    private StaplerRequest2 staplerRequest;
     private JenkinsLocationConfiguration config;
 
     @Before
     public void setUp() {
         jenkins = mock(Jenkins.class, Mockito.CALLS_REAL_METHODS);
         config = mock(JenkinsLocationConfiguration.class);
-        staplerRequest = mock(StaplerRequest.class);
+        staplerRequest = mock(StaplerRequest2.class);
     }
 
     @Test
@@ -62,7 +62,7 @@ public void getConfiguredRootUrl() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
 
             configured("http://configured.host");
 
@@ -77,7 +77,7 @@ public void getAccessedRootUrl() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
 
             accessing("https://real.host/jenkins/");
 
@@ -92,7 +92,7 @@ public void preferConfiguredOverAccessed() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
             configured("http://configured.host/");
             accessing("http://real.host/");
 
@@ -108,7 +108,7 @@ public void doNotInheritProtocolWhenDispatchingRequest() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
             configured("http://configured.host/");
             accessing("https://real.host/");
 
@@ -124,7 +124,7 @@ public void doNotInheritProtocolWhenDispatchingRequest2() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
             configured("https://ci/jenkins/");
             accessing("http://localhost:8080/");
             rootUrlIs("https://ci/jenkins/");
@@ -139,7 +139,7 @@ public void useForwardedProtoWhenPresent() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
             configured("https://ci/jenkins/");
 
             // Without a forwarded protocol, it should use the request protocol
@@ -180,7 +180,7 @@ public void useForwardedProtoWithIPv6WhenPresent() {
                 MockedStatic<Stapler> mockedStapler = mockStatic(Stapler.class)
         ) {
             mocked.when(JenkinsLocationConfiguration::get).thenReturn(config);
-            mockedStapler.when(Stapler::getCurrentRequest).thenReturn(staplerRequest);
+            mockedStapler.when(Stapler::getCurrentRequest2).thenReturn(staplerRequest);
             configured("http://[::1]/jenkins/");
 
             // Without a forwarded protocol, it should use the request protocol
@@ -219,7 +219,7 @@ private void configured(final String configuredHost) {
     }
 
     private void withHeader(String name, final String value) {
-        final StaplerRequest req = Stapler.getCurrentRequest();
+        final StaplerRequest2 req = Stapler.getCurrentRequest2();
         when(req.getHeader(name)).thenReturn(value);
     }
 
@@ -227,7 +227,7 @@ private void accessing(final String realUrl) {
 
         final URL url = getUrl(realUrl);
 
-        final StaplerRequest req = mock(StaplerRequest.class);
+        final StaplerRequest2 req = mock(StaplerRequest2.class);
         when(req.getScheme()).thenReturn(url.getProtocol());
         when(req.getServerName()).thenReturn(url.getHost());
         when(req.getServerPort()).thenReturn(url.getPort() == -1 ? "https".equals(url.getProtocol()) ? 443 : 80 : url.getPort());
@@ -235,12 +235,12 @@ private void accessing(final String realUrl) {
         when(req.getIntHeader(anyString())).thenAnswer(new Answer<Integer>() {
             @Override public Integer answer(InvocationOnMock invocation) {
                 String name = (String) invocation.getArguments()[0];
-                String value = ((StaplerRequest) invocation.getMock()).getHeader(name);
+                String value = ((StaplerRequest2) invocation.getMock()).getHeader(name);
                 return value != null ? Integer.parseInt(value) : -1;
             }
         });
 
-        when(Stapler.getCurrentRequest()).thenReturn(req);
+        when(Stapler.getCurrentRequest2()).thenReturn(req);
     }
 
     private URL getUrl(final String realUrl) {
diff --git a/core/src/test/java/jenkins/security/stapler/StaplerSignaturesTest.java b/core/src/test/java/jenkins/security/stapler/StaplerSignaturesTest.java
index 2da9082c820e..74812507e246 100644
--- a/core/src/test/java/jenkins/security/stapler/StaplerSignaturesTest.java
+++ b/core/src/test/java/jenkins/security/stapler/StaplerSignaturesTest.java
@@ -9,8 +9,8 @@
 import org.junit.Test;
 import org.kohsuke.stapler.Function;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.json.JsonResponse;
 import org.kohsuke.stapler.lang.FieldRef;
 
@@ -40,7 +40,7 @@ public static class SomeClass {
                 "staticMethod jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo int",
                 "staticMethod jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo long",
                 "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo jenkins.security.stapler.StaplerSignaturesTest$SomeClass",
-                "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doFoo org.kohsuke.stapler.StaplerRequest org.kohsuke.stapler.StaplerResponse",
+                "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doFoo org.kohsuke.stapler.StaplerRequest2 org.kohsuke.stapler.StaplerResponse2",
                 "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doWhatever java.lang.String",
                 "method java.lang.Object getClass",
                 "method java.lang.Object equals java.lang.Object",
@@ -63,7 +63,7 @@ public static void getFoo(long arg) {}
 
         public void getFoo(SomeClass arg) {}
 
-        public void doFoo(StaplerRequest req, StaplerResponse rsp) {}
+        public void doFoo(StaplerRequest2 req, StaplerResponse2 rsp) {}
 
         @StaplerDispatchable @JsonResponse
         public void doWhatever(@QueryParameter String arg) {}
@@ -91,7 +91,7 @@ public static class SomeSubclass extends SomeClass {
                 "staticMethod jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo int",
                 "staticMethod jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo long",
                 "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass getFoo jenkins.security.stapler.StaplerSignaturesTest$SomeClass",
-                "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doFoo org.kohsuke.stapler.StaplerRequest org.kohsuke.stapler.StaplerResponse",
+                "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doFoo org.kohsuke.stapler.StaplerRequest2 org.kohsuke.stapler.StaplerResponse2",
                 "method jenkins.security.stapler.StaplerSignaturesTest$SomeClass doWhatever java.lang.String",
                 "method java.lang.Object getClass",
                 "method java.lang.Object equals java.lang.Object",
diff --git a/pom.xml b/pom.xml
index c3052864caba..47a9714fef3c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -52,8 +52,7 @@ THE SOFTWARE.
   <modules>
     <module>bom</module>
     <module>websocket/spi</module>
-    <module>websocket/jetty10</module>
-    <module>websocket/jetty12-ee8</module>
+    <module>websocket/jetty12-ee9</module>
     <module>core</module>
     <module>war</module>
     <module>test</module>
@@ -98,7 +97,7 @@ THE SOFTWARE.
     <bridge-method-injector.version>1.29</bridge-method-injector.version>
     <spotless.check.skip>false</spotless.check.skip>
     <!-- Make sure to keep the jetty-maven-plugin version in war/pom.xml in sync with the Jetty release in Winstone: -->
-    <winstone.version>7.0</winstone.version>
+    <winstone.version>8.0</winstone.version>
   </properties>
 
   <!--
diff --git a/test/src/test/java/hudson/CustomPluginManagerTest.java b/test/src/test/java/hudson/CustomPluginManagerTest.java
index ff91daeaa6a3..3ce9ae08eb8d 100644
--- a/test/src/test/java/hudson/CustomPluginManagerTest.java
+++ b/test/src/test/java/hudson/CustomPluginManagerTest.java
@@ -32,10 +32,10 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
+import jakarta.servlet.ServletContext;
 import java.io.File;
 import java.lang.annotation.Retention;
 import java.lang.annotation.Target;
-import javax.servlet.ServletContext;
 import jenkins.model.Jenkins;
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/test/src/test/java/hudson/PluginManagerCheckUpdateCenterTest.java b/test/src/test/java/hudson/PluginManagerCheckUpdateCenterTest.java
index f15daf63781a..89ed65ab1b09 100644
--- a/test/src/test/java/hudson/PluginManagerCheckUpdateCenterTest.java
+++ b/test/src/test/java/hudson/PluginManagerCheckUpdateCenterTest.java
@@ -9,10 +9,10 @@
 import hudson.model.UpdateSiteTest;
 import hudson.util.HttpResponses;
 import hudson.util.Retrier;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import org.htmlunit.Page;
 import org.htmlunit.html.HtmlPage;
@@ -23,8 +23,8 @@
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.xml.sax.SAXException;
 
 public class PluginManagerCheckUpdateCenterTest {
@@ -152,7 +152,7 @@ public String getUrlName() {
             return "updateSite502";
         }
 
-        public HttpResponse doGetJson(StaplerRequest request) {
+        public HttpResponse doGetJson(StaplerRequest2 request) {
             return HttpResponses.error(502, "Gateway error");
         }
     }
@@ -175,7 +175,7 @@ public String getUrlName() {
             return "updateSiteWrongJson";
         }
 
-        public void doGetJson(StaplerRequest request, StaplerResponse response) throws IOException {
+        public void doGetJson(StaplerRequest2 request, StaplerResponse2 response) throws IOException {
             response.setContentType("text/json");
             response.setStatus(200);
             response.getWriter().append("{wrongjson}");
@@ -201,7 +201,7 @@ public String getUrlName() {
         }
 
         // The url has to end in update-center.json. See: UpdateSite#getMetadataUrlForDownloadable
-        public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException {
+        public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException {
             staplerResponse.setContentType("text/json");
             staplerResponse.setStatus(200);
             staplerResponse.serveFile(staplerRequest,  UpdateSiteTest.extract("update-center.json"));
diff --git a/test/src/test/java/hudson/PluginManagerTest.java b/test/src/test/java/hudson/PluginManagerTest.java
index 91a236db0266..b75d8fc2f66f 100644
--- a/test/src/test/java/hudson/PluginManagerTest.java
+++ b/test/src/test/java/hudson/PluginManagerTest.java
@@ -52,6 +52,7 @@
 import hudson.security.ACLContext;
 import hudson.util.FormValidation;
 import hudson.util.PersistedList;
+import jakarta.servlet.ServletException;
 import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
@@ -83,7 +84,6 @@
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
-import javax.servlet.ServletException;
 import jenkins.ClassLoaderReflectionToolkit;
 import jenkins.RestartRequiredException;
 import jenkins.model.GlobalConfiguration;
@@ -108,8 +108,8 @@
 import org.jvnet.hudson.test.Url;
 import org.jvnet.hudson.test.recipes.WithPlugin;
 import org.jvnet.hudson.test.recipes.WithPluginManager;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -178,7 +178,7 @@ public String getUrlName() {
             return "pluginManagerGetPlugin";
         }
 
-        public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException {
+        public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException {
             staplerResponse.setContentType("application/octet-stream");
             staplerResponse.setStatus(200);
             staplerResponse.serveFile(staplerRequest,  PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi"));
@@ -880,7 +880,7 @@ public String getUrlName() {
             return "security3037UpdateCenter";
         }
 
-        public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException {
+        public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException {
             staplerResponse.setContentType("application/json");
             staplerResponse.setStatus(200);
             staplerResponse.serveFile(staplerRequest, PluginManagerTest.class.getResource("/plugins/security3037-update-center.json"));
@@ -905,7 +905,7 @@ public String getUrlName() {
             return "pluginManagerGetPlugin";
         }
 
-        public void doDynamic(StaplerRequest staplerRequest, StaplerResponse staplerResponse) throws ServletException, IOException {
+        public void doDynamic(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse) throws ServletException, IOException {
             staplerResponse.setContentType("application/octet-stream");
             staplerResponse.setStatus(200);
             staplerResponse.serveFile(staplerRequest,  PluginManagerTest.class.getClassLoader().getResource("plugins/htmlpublisher.jpi"));
diff --git a/test/src/test/java/hudson/PluginTest.java b/test/src/test/java/hudson/PluginTest.java
index 79cf3703a39a..7328d36f9381 100644
--- a/test/src/test/java/hudson/PluginTest.java
+++ b/test/src/test/java/hudson/PluginTest.java
@@ -25,9 +25,9 @@
 package hudson;
 
 import hudson.model.UpdateCenter;
+import jakarta.servlet.http.HttpServletResponse;
 import java.util.List;
 import java.util.concurrent.Future;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.junit.Ignore;
 import org.junit.Rule;
diff --git a/test/src/test/java/hudson/cli/BuildCommandTest.java b/test/src/test/java/hudson/cli/BuildCommandTest.java
index 3cacae4d0177..8afae30d3edf 100644
--- a/test/src/test/java/hudson/cli/BuildCommandTest.java
+++ b/test/src/test/java/hudson/cli/BuildCommandTest.java
@@ -76,7 +76,7 @@
 import org.jvnet.hudson.test.SmokeTest;
 import org.jvnet.hudson.test.TestBuilder;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * {@link BuildCommand} test.
@@ -274,7 +274,7 @@ public ParameterValue createValue(String value) {
         }
 
         @Override
-        public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+        public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
             return createValue("BAR");
         }
 
diff --git a/test/src/test/java/hudson/cli/CLITest.java b/test/src/test/java/hudson/cli/CLITest.java
index 9471d04224b4..229a99eec51d 100644
--- a/test/src/test/java/hudson/cli/CLITest.java
+++ b/test/src/test/java/hudson/cli/CLITest.java
@@ -37,6 +37,10 @@
 import hudson.model.UnprotectedRootAction;
 import hudson.security.csrf.CrumbExclusion;
 import hudson.util.StreamTaskListener;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -46,10 +50,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.output.TeeOutputStream;
@@ -68,8 +68,8 @@
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 public class CLITest {
 
@@ -150,11 +150,11 @@ public static final class NoJenkinsAction extends CrumbExclusion implements Unpr
         }
 
         @Override public Object getTarget() {
-            doDynamic(Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+            doDynamic(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
             return this;
         }
 
-        public void doDynamic(StaplerRequest req, StaplerResponse rsp) {
+        public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) {
             rsp.setStatus(200);
         }
 
@@ -230,15 +230,15 @@ public static final class CliProxyAction extends CrumbExclusion implements Unpro
         }
 
         @Override public Object getTarget() {
-            throw doDynamic(Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+            throw doDynamic(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
         }
 
-        public HttpResponses.HttpResponseException doDynamic(StaplerRequest req, StaplerResponse rsp) {
+        public HttpResponses.HttpResponseException doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) {
             final String url = req.getRequestURIWithQueryString().replaceFirst("/cli-proxy", "");
             // Custom written redirect so no traces of Jenkins are present in headers
             return new HttpResponses.HttpResponseException() {
                 @Override
-                public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException {
+                public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException {
                     rsp.setHeader("Location", url);
                     rsp.setContentType("text/html");
                     rsp.setStatus(HttpURLConnection.HTTP_MOVED_TEMP);
diff --git a/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java b/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java
index 2124f8c19755..54f68a43b66c 100644
--- a/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java
+++ b/test/src/test/java/hudson/diagnosis/OldDataMonitorTest.java
@@ -92,7 +92,7 @@ public class OldDataMonitorTest {
     /**
      * Note that this doesn't actually run slowly, it just ensures that
      * the {@link OldDataMonitor#changeListener}'s {@code onChange()} can complete
-     * while {@link OldDataMonitor#doDiscard(org.kohsuke.stapler.StaplerRequest, org.kohsuke.stapler.StaplerResponse)}
+     * while {@link OldDataMonitor#doDiscard(org.kohsuke.stapler.StaplerRequest2, org.kohsuke.stapler.StaplerResponse2)}
      * is still running.
      *
      */
@@ -114,7 +114,7 @@ public class OldDataMonitorTest {
         ExecutorService executors = Executors.newSingleThreadExecutor();
 
         Future<Void> discardFuture = executors.submit(() -> {
-            oldDataMonitor.doDiscard(Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+            oldDataMonitor.doDiscard(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
             return null;
         });
 
diff --git a/test/src/test/java/hudson/model/ApiTest.java b/test/src/test/java/hudson/model/ApiTest.java
index 7422ec78fd98..1ac268423114 100644
--- a/test/src/test/java/hudson/model/ApiTest.java
+++ b/test/src/test/java/hudson/model/ApiTest.java
@@ -32,10 +32,10 @@
 import static org.junit.Assert.fail;
 
 import edu.umd.cs.findbugs.annotations.CheckForNull;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.File;
 import java.io.IOException;
 import java.net.HttpURLConnection;
-import javax.servlet.http.HttpServletResponse;
 import net.sf.json.JSONObject;
 import org.htmlunit.Page;
 import org.htmlunit.WebResponse;
diff --git a/test/src/test/java/hudson/model/ComputerConfigDotXmlTest.java b/test/src/test/java/hudson/model/ComputerConfigDotXmlTest.java
index ce7f987ad532..8eea0a4a7890 100644
--- a/test/src/test/java/hudson/model/ComputerConfigDotXmlTest.java
+++ b/test/src/test/java/hudson/model/ComputerConfigDotXmlTest.java
@@ -43,6 +43,10 @@
 import hudson.security.AccessDeniedException3;
 import hudson.security.GlobalMatrixAuthorizationStrategy;
 import hudson.slaves.DumbSlave;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletOutputStream;
+import jakarta.servlet.WriteListener;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
@@ -50,10 +54,6 @@
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletOutputStream;
-import javax.servlet.WriteListener;
 import jenkins.model.Jenkins;
 import org.htmlunit.FailingHttpStatusCodeException;
 import org.htmlunit.HttpMethod;
@@ -68,8 +68,8 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.PretendSlave;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.springframework.security.core.context.SecurityContext;
@@ -85,8 +85,8 @@ public class ComputerConfigDotXmlTest {
     @Rule
     public final TemporaryFolder temporaryFolder = new TemporaryFolder();
 
-    @Mock private StaplerRequest req;
-    @Mock private StaplerResponse rsp;
+    @Mock private StaplerRequest2 req;
+    @Mock private StaplerResponse2 rsp;
 
     private Computer computer;
     private SecurityContext oldSecurityContext;
diff --git a/test/src/test/java/hudson/model/DescriptorTest.java b/test/src/test/java/hudson/model/DescriptorTest.java
index 2a0b09d74b79..d608360e69ed 100644
--- a/test/src/test/java/hudson/model/DescriptorTest.java
+++ b/test/src/test/java/hudson/model/DescriptorTest.java
@@ -49,7 +49,7 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @SuppressWarnings({"unchecked", "rawtypes"})
 public class DescriptorTest {
@@ -115,7 +115,7 @@ private static final class DescriptorImpl extends BuildStepDescriptor<Builder> {
             return id;
         }
 
-        @Override public Builder newInstance(StaplerRequest req, JSONObject formData) {
+        @Override public Builder newInstance(StaplerRequest2 req, JSONObject formData) {
             return new BuilderImpl(id);
         }
 
@@ -213,7 +213,7 @@ public D3D(String id) {
             return id;
         }
 
-        @Override public D3 newInstance(StaplerRequest req, JSONObject formData) {
+        @Override public D3 newInstance(StaplerRequest2 req, JSONObject formData) {
             return new D3(id);
         }
     }
@@ -242,7 +242,7 @@ public void presentStacktraceFromFormException() {
         final Descriptor.FormException fe = new Descriptor.FormException("My Message", cause, "fake");
         FailingHttpStatusCodeException ex = assertThrows(FailingHttpStatusCodeException.class, () ->
             rule.executeOnServer((Callable<Void>) () -> {
-                fe.generateResponse(Stapler.getCurrentRequest(), Stapler.getCurrentResponse(), Jenkins.get());
+                fe.generateResponse(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2(), Jenkins.get());
                 return null;
             }));
         String response = ex.getResponse().getContentAsString();
diff --git a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java
index 24c978e78f8d..fbd1173909df 100644
--- a/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java
+++ b/test/src/test/java/hudson/model/DirectoryBrowserSupportTest.java
@@ -97,8 +97,8 @@
 import org.jvnet.hudson.test.SingleFileSCM;
 import org.jvnet.hudson.test.TestBuilder;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -381,7 +381,7 @@ public String getDisplayName() {
             return null;
         }
 
-        public void doDynamic(StaplerRequest req, StaplerResponse rsp) throws Exception {
+        public void doDynamic(StaplerRequest2 req, StaplerResponse2 rsp) throws Exception {
             String hash = req.getRestOfPath().substring(1);
             for (byte[] file : files) {
                 if (Util.getDigestOf(new ByteArrayInputStream(file)).equals(hash)) {
diff --git a/test/src/test/java/hudson/model/JobPropertyTest.java b/test/src/test/java/hudson/model/JobPropertyTest.java
index ecd16a70fae7..97343823e332 100644
--- a/test/src/test/java/hudson/model/JobPropertyTest.java
+++ b/test/src/test/java/hudson/model/JobPropertyTest.java
@@ -41,7 +41,7 @@
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class JobPropertyTest {
 
@@ -124,7 +124,7 @@ public JobPropertyWithConfigImpl(String name) {
         @TestExtension("configRoundtrip")
         public static class DescriptorImpl extends JobPropertyDescriptor {
             @Override
-            public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData) throws FormException {
+            public JobProperty<?> newInstance(StaplerRequest2 req, JSONObject formData) throws FormException {
                 JobPropertyWithConfigImpl prop = (JobPropertyWithConfigImpl) super.newInstance(req, formData);
                 return prop.name.isEmpty() ? null : prop;
             }
@@ -147,7 +147,7 @@ public static class InvisibleImpl extends JobProperty<Job<?, ?>> {
         InvisibleImpl() {}
 
         @Override
-        public JobProperty<?> reconfigure(StaplerRequest req, JSONObject form) {
+        public JobProperty<?> reconfigure(StaplerRequest2 req, JSONObject form) {
             return this;
         }
 
diff --git a/test/src/test/java/hudson/model/ListViewTest.java b/test/src/test/java/hudson/model/ListViewTest.java
index 4eef645d6608..c401cc3f9001 100644
--- a/test/src/test/java/hudson/model/ListViewTest.java
+++ b/test/src/test/java/hudson/model/ListViewTest.java
@@ -46,6 +46,8 @@
 import hudson.security.Permission;
 import hudson.views.StatusFilter;
 import hudson.views.ViewJobFilter;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
@@ -58,8 +60,6 @@
 import java.util.Set;
 import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicBoolean;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
 import jenkins.model.Jenkins;
 import org.apache.commons.io.IOUtils;
 import org.htmlunit.AlertHandler;
@@ -75,8 +75,8 @@
 import org.jvnet.hudson.test.JenkinsRule.WebClient;
 import org.jvnet.hudson.test.MockFolder;
 import org.jvnet.hudson.test.recipes.LocalData;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.springframework.security.core.Authentication;
 import org.xml.sax.SAXException;
 
@@ -258,8 +258,8 @@ private void checkLinkFromItemExistsAndIsValid(Item item, ItemGroup ig, Item top
     @Test public void addJobUsingAPI() throws Exception {
         ListView v = new ListView("view", j.jenkins);
         j.jenkins.addView(v);
-        StaplerRequest req = mock(StaplerRequest.class);
-        StaplerResponse rsp = mock(StaplerResponse.class);
+        StaplerRequest2 req = mock(StaplerRequest2.class);
+        StaplerResponse2 rsp = mock(StaplerResponse2.class);
 
         String configXml = IOUtils.toString(getClass().getResourceAsStream(String.format("%s/%s/config.xml", getClass().getSimpleName(), testName.getMethodName())), StandardCharsets.UTF_8);
 
diff --git a/test/src/test/java/hudson/model/ParametersDefinitionPropertyTest.java b/test/src/test/java/hudson/model/ParametersDefinitionPropertyTest.java
index 54d3b3a0c847..732deb13d767 100644
--- a/test/src/test/java/hudson/model/ParametersDefinitionPropertyTest.java
+++ b/test/src/test/java/hudson/model/ParametersDefinitionPropertyTest.java
@@ -43,7 +43,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class ParametersDefinitionPropertyTest {
 
@@ -79,12 +79,12 @@ public KrazyParameterDefinition(String name, String description, String field) {
         }
 
         @Override
-        public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
+        public ParameterValue createValue(StaplerRequest2 req, JSONObject jo) {
             throw new UnsupportedOperationException();
         }
 
         @Override
-        public ParameterValue createValue(StaplerRequest req) {
+        public ParameterValue createValue(StaplerRequest2 req) {
             throw new UnsupportedOperationException();
         }
 
@@ -92,7 +92,7 @@ public ParameterValue createValue(StaplerRequest req) {
         public static class DescriptorImpl extends ParameterDescriptor {
 
             @Override
-            public ParameterDefinition newInstance(StaplerRequest req, JSONObject formData) {
+            public ParameterDefinition newInstance(StaplerRequest2 req, JSONObject formData) {
                 return new KrazyParameterDefinition(formData.getString("name"), formData.getString("description"), formData.getString("field").toLowerCase(Locale.ENGLISH));
             }
 
diff --git a/test/src/test/java/hudson/model/ProjectTest.java b/test/src/test/java/hudson/model/ProjectTest.java
index e3f2d84493e3..389837e46a42 100644
--- a/test/src/test/java/hudson/model/ProjectTest.java
+++ b/test/src/test/java/hudson/model/ProjectTest.java
@@ -108,6 +108,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestBuilder;
 import org.jvnet.hudson.test.TestExtension;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  *
@@ -573,7 +574,7 @@ public void testDoDoDelete() throws Exception {
         j.jenkins.setSecurityRealm(j.createDummySecurityRealm());
         User user = User.getById("john", true);
         try (ACLContext as = ACL.as(user)) {
-            assertThrows("User should not have permission to build project", AccessDeniedException3.class, () -> project.doDoDelete(null, null));
+            assertThrows("User should not have permission to build project", AccessDeniedException3.class, () -> project.doDoDelete((StaplerRequest2) null, null));
         }
         auth.add(Jenkins.READ, user.getId());
         auth.add(Item.READ, user.getId());
diff --git a/test/src/test/java/hudson/model/QueueTest.java b/test/src/test/java/hudson/model/QueueTest.java
index fa76fd88ae0d..a28f6bae0da5 100644
--- a/test/src/test/java/hudson/model/QueueTest.java
+++ b/test/src/test/java/hudson/model/QueueTest.java
@@ -78,6 +78,7 @@
 import hudson.triggers.SCMTrigger.SCMTriggerCause;
 import hudson.triggers.TimerTrigger.TimerTriggerCause;
 import hudson.util.OneShotEvent;
+import jakarta.servlet.ServletException;
 import java.io.File;
 import java.io.IOException;
 import java.io.UncheckedIOException;
@@ -101,7 +102,6 @@
 import java.util.function.Function;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.ServletException;
 import jenkins.model.BlockedBecauseOfBuildInProgress;
 import jenkins.model.Jenkins;
 import jenkins.model.queue.QueueIdStrategy;
diff --git a/test/src/test/java/hudson/model/UpdateCenterCustomTest.java b/test/src/test/java/hudson/model/UpdateCenterCustomTest.java
index dc37e2b3c875..2a3a9296c1be 100644
--- a/test/src/test/java/hudson/model/UpdateCenterCustomTest.java
+++ b/test/src/test/java/hudson/model/UpdateCenterCustomTest.java
@@ -28,7 +28,7 @@
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.instanceOf;
 
-import javax.servlet.ServletContext;
+import jakarta.servlet.ServletContext;
 import org.junit.Rule;
 import org.junit.Test;
 import org.jvnet.hudson.test.JenkinsRule;
@@ -59,10 +59,10 @@ private static final class CustomUpdateCenterRule extends JenkinsRule {
         }
 
         @Override
-        protected ServletContext createWebServer() throws Exception {
+        protected ServletContext createWebServer2() throws Exception {
             _oldValue = System.getProperty(PROPERTY_NAME);
             System.setProperty(PROPERTY_NAME, updateCenterClassName);
-            return super.createWebServer();
+            return super.createWebServer2();
         }
 
         @Override
diff --git a/test/src/test/java/hudson/model/UsageStatisticsTest.java b/test/src/test/java/hudson/model/UsageStatisticsTest.java
index 015203308e25..bffd2af0f445 100644
--- a/test/src/test/java/hudson/model/UsageStatisticsTest.java
+++ b/test/src/test/java/hudson/model/UsageStatisticsTest.java
@@ -116,7 +116,7 @@ public void roundtrip() throws Exception {
         // that would cause issues with parsing/analyzing uploaded usage statistics
         assertEquals(1, o.getInt("stat"));
         assertEquals(jenkins.getLegacyInstanceId(), o.getString("install"));
-        assertEquals(jenkins.servletContext.getServerInfo(), o.getString("servletContainer"));
+        assertEquals(jenkins.getServletContext().getServerInfo(), o.getString("servletContainer"));
         assertEquals(Jenkins.VERSION, o.getString("version"));
 
         assertTrue(o.has("plugins"));
diff --git a/test/src/test/java/hudson/model/ViewDescriptorTest.java b/test/src/test/java/hudson/model/ViewDescriptorTest.java
index facfaecd1d77..b4e34cf5a701 100644
--- a/test/src/test/java/hudson/model/ViewDescriptorTest.java
+++ b/test/src/test/java/hudson/model/ViewDescriptorTest.java
@@ -42,7 +42,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.MockFolder;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class ViewDescriptorTest {
 
@@ -156,7 +156,7 @@ public String getSomeProperty() {
         }
 
         @Override
-        public ViewProperty reconfigure(StaplerRequest req, JSONObject form) {
+        public ViewProperty reconfigure(StaplerRequest2 req, JSONObject form) {
             return this;
         }
 
diff --git a/test/src/test/java/hudson/model/ViewPropertyTest.java b/test/src/test/java/hudson/model/ViewPropertyTest.java
index 6ebad1958b1d..4f253bb9971f 100644
--- a/test/src/test/java/hudson/model/ViewPropertyTest.java
+++ b/test/src/test/java/hudson/model/ViewPropertyTest.java
@@ -38,7 +38,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -100,7 +100,7 @@ public static class InvisiblePropertyImpl extends ViewProperty {
         }
 
         @Override
-        public ViewProperty reconfigure(StaplerRequest req, JSONObject form) {
+        public ViewProperty reconfigure(StaplerRequest2 req, JSONObject form) {
             return this;
         }
 
diff --git a/test/src/test/java/hudson/model/ViewTest.java b/test/src/test/java/hudson/model/ViewTest.java
index 4355d82ad063..63dd879d25cc 100644
--- a/test/src/test/java/hudson/model/ViewTest.java
+++ b/test/src/test/java/hudson/model/ViewTest.java
@@ -100,8 +100,8 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.jvnet.hudson.test.recipes.LocalData;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.w3c.dom.Text;
 
 /**
@@ -488,7 +488,7 @@ public void testSave() throws Exception {
         view.save();
         j.jenkins.doReload();
         //wait until all configuration are reloaded
-        if (j.jenkins.servletContext.getAttribute("app") instanceof HudsonIsLoading) {
+        if (j.jenkins.getServletContext().getAttribute("app") instanceof HudsonIsLoading) {
             Thread.sleep(500);
         }
         assertTrue("View does not contains job free after load.", j.jenkins.getView(view.getDisplayName()).contains(j.jenkins.getItem(job.getName())));
@@ -1081,11 +1081,11 @@ public boolean contains(TopLevelItem item) {
         }
 
         @Override
-        protected void submit(StaplerRequest req) {
+        protected void submit(StaplerRequest2 req) {
         }
 
         @Override
-        public Item doCreateItem(StaplerRequest req, StaplerResponse rsp) {
+        public Item doCreateItem(StaplerRequest2 req, StaplerResponse2 rsp) {
             return null;
         }
     }
diff --git a/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java b/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java
index 83f9bc9f20a0..7265655b4982 100644
--- a/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java
+++ b/test/src/test/java/hudson/pages/SystemConfigurationTestCase.java
@@ -35,7 +35,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class SystemConfigurationTestCase {
 
@@ -70,7 +70,7 @@ private static class PageDecoratorImpl extends PageDecorator {
         private String decoratorId;
 
         @Override
-        public boolean configure(StaplerRequest req, JSONObject json) {
+        public boolean configure(StaplerRequest2 req, JSONObject json) {
             decoratorId = json.getString("decoratorId");
             return true;
         }
diff --git a/test/src/test/java/hudson/security/LoginTest.java b/test/src/test/java/hudson/security/LoginTest.java
index 0829a6bc41f6..30b016d717c4 100644
--- a/test/src/test/java/hudson/security/LoginTest.java
+++ b/test/src/test/java/hudson/security/LoginTest.java
@@ -1,6 +1,6 @@
 package hudson.security;
 
-import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
+import static jakarta.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertFalse;
diff --git a/test/src/test/java/hudson/security/SecurityRealmTest.java b/test/src/test/java/hudson/security/SecurityRealmTest.java
index 6ebe98e71bf1..5121086085b2 100644
--- a/test/src/test/java/hudson/security/SecurityRealmTest.java
+++ b/test/src/test/java/hudson/security/SecurityRealmTest.java
@@ -152,10 +152,10 @@ public void getPostLogOutUrl() throws Exception {
         j.jenkins.setSecurityRealm(osr);
         j.executeOnServer(() -> {
             assertEquals("/jenkins/", j.jenkins.getSecurityRealm().getPostLogOutUrl(Stapler.getCurrentRequest(), Jenkins.ANONYMOUS));
-            assertEquals("/jenkins/", j.jenkins.getSecurityRealm().getPostLogOutUrl2(Stapler.getCurrentRequest(), Jenkins.ANONYMOUS2));
+            assertEquals("/jenkins/", j.jenkins.getSecurityRealm().getPostLogOutUrl2(Stapler.getCurrentRequest2(), Jenkins.ANONYMOUS2));
             osr.special = true;
             assertEquals("/jenkins/custom", j.jenkins.getSecurityRealm().getPostLogOutUrl(Stapler.getCurrentRequest(), Jenkins.ANONYMOUS));
-            assertEquals("/jenkins/custom", j.jenkins.getSecurityRealm().getPostLogOutUrl2(Stapler.getCurrentRequest(), Jenkins.ANONYMOUS2));
+            assertEquals("/jenkins/custom", j.jenkins.getSecurityRealm().getPostLogOutUrl2(Stapler.getCurrentRequest2(), Jenkins.ANONYMOUS2));
             return null;
         });
     }
diff --git a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java
index e7597adaf8fd..0798c39ad2cd 100644
--- a/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java
+++ b/test/src/test/java/hudson/security/TokenBasedRememberMeServices2Test.java
@@ -299,7 +299,7 @@ public void rememberMeToken_shouldLoadUserDetailsOnlyOnce() throws Exception {
         JenkinsRule.WebClient wc = j.createWebClient();
         wc.getCookieManager().addCookie(cookie);
         // trigger remember me
-        String sessionSeed = wc.executeOnServer(() -> Stapler.getCurrentRequest().getSession(false).getAttribute(UserSeedProperty.USER_SESSION_SEED).toString());
+        String sessionSeed = wc.executeOnServer(() -> Stapler.getCurrentRequest2().getSession(false).getAttribute(UserSeedProperty.USER_SESSION_SEED).toString());
         realm.verifyInvocations(1);
         String userSeed = alice.getProperty(UserSeedProperty.class).getSeed();
 
diff --git a/test/src/test/java/hudson/security/WhoAmITest.java b/test/src/test/java/hudson/security/WhoAmITest.java
index 819b98984e88..a92b25f0269c 100644
--- a/test/src/test/java/hudson/security/WhoAmITest.java
+++ b/test/src/test/java/hudson/security/WhoAmITest.java
@@ -31,11 +31,11 @@
 import static org.hamcrest.Matchers.nullValue;
 
 import hudson.model.User;
+import jakarta.servlet.http.HttpSession;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.Collection;
 import java.util.Collections;
-import javax.servlet.http.HttpSession;
 import jenkins.model.Jenkins;
 import jenkins.security.ApiTokenProperty;
 import jenkins.security.apitoken.TokenUuidAndPlainValue;
@@ -73,7 +73,7 @@ public void whoAmI_regular_doesNotProvideSensitiveInformation() throws Exception
         String content = whoAmIPage.getWebResponse().getContentAsString();
 
         String sessionId = wc.executeOnServer(() -> {
-            HttpSession session = Stapler.getCurrentRequest().getSession(false);
+            HttpSession session = Stapler.getCurrentRequest2().getSession(false);
             return session != null ? session.getId() : null;
         });
 
@@ -114,7 +114,7 @@ public void whoAmI_regularApi_doesNotProvideSensitiveInformation() throws Except
         String content = whoAmIPage.getWebResponse().getContentAsString();
 
         String sessionId = wc.executeOnServer(() -> {
-            HttpSession session = Stapler.getCurrentRequest().getSession(false);
+            HttpSession session = Stapler.getCurrentRequest2().getSession(false);
             return session != null ? session.getId() : null;
         });
 
diff --git a/test/src/test/java/hudson/security/csrf/CrumbExclusionTest.java b/test/src/test/java/hudson/security/csrf/CrumbExclusionTest.java
index adb2184ff239..def3f5746783 100644
--- a/test/src/test/java/hudson/security/csrf/CrumbExclusionTest.java
+++ b/test/src/test/java/hudson/security/csrf/CrumbExclusionTest.java
@@ -31,12 +31,12 @@
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.ExtensionList;
 import hudson.model.UnprotectedRootAction;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.net.URL;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import org.htmlunit.FailingHttpStatusCodeException;
 import org.htmlunit.HttpMethod;
diff --git a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java
index 2904af69fc4d..65141fa93cdd 100644
--- a/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java
+++ b/test/src/test/java/hudson/security/csrf/DefaultCrumbIssuerTest.java
@@ -16,9 +16,9 @@
 import static org.junit.Assert.assertTrue;
 
 import hudson.model.User;
+import jakarta.servlet.http.HttpServletResponse;
 import java.net.HttpURLConnection;
 import java.net.URI;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONObject;
 import org.htmlunit.FailingHttpStatusCodeException;
diff --git a/test/src/test/java/hudson/slaves/CloudTest.java b/test/src/test/java/hudson/slaves/CloudTest.java
index 7ad4dff33aa6..04bb7a04f212 100644
--- a/test/src/test/java/hudson/slaves/CloudTest.java
+++ b/test/src/test/java/hudson/slaves/CloudTest.java
@@ -28,7 +28,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.jvnet.hudson.test.WithoutJenkins;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 
 public class CloudTest {
 
@@ -127,7 +127,7 @@ public static final class TaskCloudAction implements Action {
             return "task";
         }
 
-        public void doIndex(StaplerResponse rsp) throws IOException {
+        public void doIndex(StaplerResponse2 rsp) throws IOException {
             rsp.getOutputStream().println("doIndex called");
         }
     }
diff --git a/test/src/test/java/hudson/slaves/NodePropertyTest.java b/test/src/test/java/hudson/slaves/NodePropertyTest.java
index 6aef28929b11..dc78979910fe 100644
--- a/test/src/test/java/hudson/slaves/NodePropertyTest.java
+++ b/test/src/test/java/hudson/slaves/NodePropertyTest.java
@@ -19,7 +19,7 @@
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -52,7 +52,7 @@ public static class InvisibleProperty extends NodeProperty<Slave> {
         boolean reconfigured = false;
 
         @Override
-        public NodeProperty<?> reconfigure(StaplerRequest req, JSONObject form) {
+        public NodeProperty<?> reconfigure(StaplerRequest2 req, JSONObject form) {
             reconfigured = true;
             return this;
         }
diff --git a/test/src/test/java/hudson/util/BootFailureTest.java b/test/src/test/java/hudson/util/BootFailureTest.java
index d083a74a2e26..b8ba0bd8a630 100644
--- a/test/src/test/java/hudson/util/BootFailureTest.java
+++ b/test/src/test/java/hudson/util/BootFailureTest.java
@@ -8,6 +8,8 @@
 import hudson.WebAppMain;
 import hudson.model.Hudson;
 import hudson.model.listeners.ItemListener;
+import jakarta.servlet.ServletContext;
+import jakarta.servlet.ServletContextEvent;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -16,8 +18,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletContextEvent;
 import jenkins.model.Jenkins;
 import org.junit.After;
 import org.junit.Rule;
@@ -25,7 +25,7 @@
 import org.junit.rules.TemporaryFolder;
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
-import org.jvnet.hudson.test.NoListenerConfiguration;
+import org.jvnet.hudson.test.NoListenerConfiguration2;
 import org.jvnet.hudson.test.TestEnvironment;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.WebApp;
@@ -66,13 +66,13 @@ public WebAppMain.FileAndDescription getHomeDir(ServletContextEvent event) {
             // Without this gymnastic, the jenkins-test-harness adds a NoListenerConfiguration
             // that prevents us to inject our own custom WebAppMain
             // With this approach we can make the server calls the regular contextInitialized
-            ServletContext ws = createWebServer((context, server) -> {
-                NoListenerConfiguration noListenerConfiguration = context.getBean(NoListenerConfiguration.class);
+            ServletContext ws = createWebServer2((context, server) -> {
+                NoListenerConfiguration2 noListenerConfiguration = context.getBean(NoListenerConfiguration2.class);
                 // future-proof
                 assertNotNull(noListenerConfiguration);
                 if (noListenerConfiguration != null) {
                     context.removeBean(noListenerConfiguration);
-                    context.addBean(new NoListenerConfiguration(context) {
+                    context.addBean(new NoListenerConfiguration2(context) {
                         @Override
                         protected void doStart() {
                             // default behavior of noListenerConfiguration
diff --git a/test/src/test/java/hudson/util/HudsonIsLoadingTest.java b/test/src/test/java/hudson/util/HudsonIsLoadingTest.java
index 21ae31734e30..0a49084ad336 100644
--- a/test/src/test/java/hudson/util/HudsonIsLoadingTest.java
+++ b/test/src/test/java/hudson/util/HudsonIsLoadingTest.java
@@ -1,6 +1,6 @@
 package hudson.util;
 
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
@@ -19,7 +19,7 @@ public class HudsonIsLoadingTest {
     @Test
     @Issue("JENKINS-55062")
     public void withPrefix() throws Exception {
-        j.jenkins.servletContext.setAttribute("app", new HudsonIsLoading());
+        j.jenkins.getServletContext().setAttribute("app", new HudsonIsLoading());
         JenkinsRule.WebClient wc = j.createWebClient()
                 // this is a failure page already
                 .withThrowExceptionOnFailingStatusCode(false)
diff --git a/test/src/test/java/hudson/util/HudsonIsRestartingTest.java b/test/src/test/java/hudson/util/HudsonIsRestartingTest.java
index 464f16e72da9..d70ea9c33959 100644
--- a/test/src/test/java/hudson/util/HudsonIsRestartingTest.java
+++ b/test/src/test/java/hudson/util/HudsonIsRestartingTest.java
@@ -1,6 +1,6 @@
 package hudson.util;
 
-import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
+import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
 import static org.junit.Assert.assertEquals;
@@ -20,7 +20,7 @@ public class HudsonIsRestartingTest {
     @Test
     @Issue("JENKINS-55062")
     public void withPrefix() throws Exception {
-        j.jenkins.servletContext.setAttribute("app", new HudsonIsRestarting(false));
+        j.jenkins.getServletContext().setAttribute("app", new HudsonIsRestarting(false));
         JenkinsRule.WebClient wc = j.createWebClient()
                 // this is a failure page already
                 .withThrowExceptionOnFailingStatusCode(false)
diff --git a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java
index ff0b255114e1..570c4dfb8f04 100644
--- a/test/src/test/java/hudson/util/RobustReflectionConverterTest.java
+++ b/test/src/test/java/hudson/util/RobustReflectionConverterTest.java
@@ -61,7 +61,7 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.jvnet.hudson.test.recipes.LocalData;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class RobustReflectionConverterTest {
 
@@ -123,7 +123,7 @@ public String getDisplayName() {
             }
 
             @Override
-            public AcceptOnlySpecificKeyword newInstance(StaplerRequest req, JSONObject formData)
+            public AcceptOnlySpecificKeyword newInstance(StaplerRequest2 req, JSONObject formData)
                     throws FormException {
                 AcceptOnlySpecificKeyword instance = super.newInstance(req, formData);
                 if (!instance.isAcceptable()) {
@@ -160,7 +160,7 @@ public String getDisplayName() {
             }
 
             @Override
-            public JobProperty<?> newInstance(StaplerRequest req, JSONObject formData)
+            public JobProperty<?> newInstance(StaplerRequest2 req, JSONObject formData)
                     throws FormException {
                 // unfortunately, default newInstance bypasses newInstances for members.
                 formData = formData.getJSONObject("keywordProperty");
diff --git a/test/src/test/java/hudson/util/XStream2Security383Test.java b/test/src/test/java/hudson/util/XStream2Security383Test.java
index 2d8002eb4a9e..6fe7b5377e81 100644
--- a/test/src/test/java/hudson/util/XStream2Security383Test.java
+++ b/test/src/test/java/hudson/util/XStream2Security383Test.java
@@ -5,14 +5,14 @@
 import static org.mockito.Mockito.when;
 
 import hudson.model.Items;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.util.logging.Level;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
 import jenkins.security.ClassFilterImpl;
 import org.apache.commons.io.IOUtils;
 import org.junit.After;
@@ -23,8 +23,8 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.LoggerRule;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -40,10 +40,10 @@ public class XStream2Security383Test {
     public LoggerRule logging = new LoggerRule().record(ClassFilterImpl.class, Level.FINE);
 
     @Mock
-    private StaplerRequest req;
+    private StaplerRequest2 req;
 
     @Mock
-    private StaplerResponse rsp;
+    private StaplerResponse2 rsp;
 
     private AutoCloseable mocks;
 
diff --git a/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java b/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java
index ca0a67e4fe42..7a6de7d6c55f 100644
--- a/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java
+++ b/test/src/test/java/hudson/views/GlobalDefaultViewConfigurationTest.java
@@ -35,7 +35,7 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.kohsuke.stapler.MockStaplerRequestBuilder;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Tests of {@link GlobalDefaultViewConfiguration}.
@@ -52,7 +52,7 @@ public void shouldNotFailIfTheDefaultViewIsMissing() {
         String viewName = "NonExistentView";
         GlobalDefaultViewConfiguration c = new GlobalDefaultViewConfiguration();
 
-        StaplerRequest create = new MockStaplerRequestBuilder(j, "/configure").build();
+        StaplerRequest2 create = new MockStaplerRequestBuilder(j, "/configure").build();
         JSONObject params = new JSONObject();
         params.accumulate("primaryView", viewName);
         try {
diff --git a/test/src/test/java/jenkins/diagnostics/URICheckEncodingMonitorTest.java b/test/src/test/java/jenkins/diagnostics/URICheckEncodingMonitorTest.java
index ca3fd62b9e4e..dc444f431de5 100644
--- a/test/src/test/java/jenkins/diagnostics/URICheckEncodingMonitorTest.java
+++ b/test/src/test/java/jenkins/diagnostics/URICheckEncodingMonitorTest.java
@@ -22,7 +22,7 @@ public class URICheckEncodingMonitorTest {
     public void emptyValueInResponse() throws Exception {
         j.executeOnServer(() -> {
                 URICheckEncodingMonitor monitor = new URICheckEncodingMonitor();
-                FormValidation validation = monitor.doCheckURIEncoding(Stapler.getCurrentRequest());
+                FormValidation validation = monitor.doCheckURIEncoding(Stapler.getCurrentRequest2());
                 assertThat(validation.kind, is(FormValidation.Kind.WARNING));
                 assertThat(validation.getMessage(), containsString("Your container doesn’t use UTF-8 to decode URLs."));
                 return null;
diff --git a/test/src/test/java/jenkins/install/InstallUtilTest.java b/test/src/test/java/jenkins/install/InstallUtilTest.java
index 9a7d6534f1a4..0047ecc5aa31 100644
--- a/test/src/test/java/jenkins/install/InstallUtilTest.java
+++ b/test/src/test/java/jenkins/install/InstallUtilTest.java
@@ -33,6 +33,7 @@
 import hudson.model.UpdateCenter.DownloadJob.Success;
 import hudson.model.UpdateCenter.UpdateCenterJob;
 import hudson.model.UpdateSite;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -40,7 +41,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-import javax.servlet.ServletException;
 import jenkins.model.Jenkins;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
diff --git a/test/src/test/java/jenkins/model/ContextMenuTest.java b/test/src/test/java/jenkins/model/ContextMenuTest.java
index 313455de02fd..37c994d89017 100644
--- a/test/src/test/java/jenkins/model/ContextMenuTest.java
+++ b/test/src/test/java/jenkins/model/ContextMenuTest.java
@@ -55,7 +55,7 @@ public class ContextMenuTest {
     @Issue("JENKINS-19173")
     @Test public void contextMenuVisibility() throws Exception {
         final FreeStyleProject p = j.createFreeStyleProject("p");
-        Callable<ContextMenu> doContextMenu = () -> p.doContextMenu(Stapler.getCurrentRequest(), Stapler.getCurrentResponse());
+        Callable<ContextMenu> doContextMenu = () -> p.doContextMenu(Stapler.getCurrentRequest2(), Stapler.getCurrentResponse2());
         ActionFactory f = j.jenkins.getExtensionList(TransientProjectActionFactory.class).get(ActionFactory.class);
         f.visible = true;
         ContextMenu menu = j.executeOnServer(doContextMenu);
diff --git a/test/src/test/java/jenkins/model/GlobalSCMRetryCountConfigurationTest.java b/test/src/test/java/jenkins/model/GlobalSCMRetryCountConfigurationTest.java
index 3d42450274e3..74e612cc8432 100644
--- a/test/src/test/java/jenkins/model/GlobalSCMRetryCountConfigurationTest.java
+++ b/test/src/test/java/jenkins/model/GlobalSCMRetryCountConfigurationTest.java
@@ -52,17 +52,17 @@ public void shouldExceptOnNullScmRetryCount() throws Exception {
                     GlobalConfiguration.all().getDynamic("jenkins.model.GlobalSCMRetryCountConfiguration");
 
             json.element("scmCheckoutRetryCount", 5);
-            gc.configure(Stapler.getCurrentRequest(), json);
+            gc.configure(Stapler.getCurrentRequest2(), json);
             assertThat("Wrong value, it should be equal to 5",
                     j.getInstance().getScmCheckoutRetryCount(), equalTo(5));
 
             json.element("scmCheckoutRetryCount", 3);
-            gc.configure(Stapler.getCurrentRequest(), json);
+            gc.configure(Stapler.getCurrentRequest2(), json);
             assertThat("Wrong value, it should be equal to 3",
                     j.getInstance().getScmCheckoutRetryCount(), equalTo(3));
 
             JSONObject emptyJson = new JSONObject();
-            gc.configure(Stapler.getCurrentRequest(), emptyJson);
+            gc.configure(Stapler.getCurrentRequest2(), emptyJson);
         } catch (Descriptor.FormException e) {
             assertThat("Scm Retry count value changed! This shouldn't happen.",
                     j.getInstance().getScmCheckoutRetryCount(), equalTo(3));
diff --git a/test/src/test/java/jenkins/model/ParameterizedJobMixInTest.java b/test/src/test/java/jenkins/model/ParameterizedJobMixInTest.java
index f873a69d30e6..c066ce6452cb 100644
--- a/test/src/test/java/jenkins/model/ParameterizedJobMixInTest.java
+++ b/test/src/test/java/jenkins/model/ParameterizedJobMixInTest.java
@@ -34,8 +34,8 @@
 import hudson.model.ParametersDefinitionProperty;
 import hudson.model.Queue;
 import hudson.model.StringParameterDefinition;
+import jakarta.servlet.http.HttpServletResponse;
 import java.net.URL;
-import javax.servlet.http.HttpServletResponse;
 import org.htmlunit.FailingHttpStatusCodeException;
 import org.htmlunit.HttpMethod;
 import org.htmlunit.WebRequest;
@@ -45,6 +45,7 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 
+
 /**
  * Tests of {@link ParameterizedJobMixIn}.
  * @author Oleg Nenashev
diff --git a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java
index 162ac231b664..cd4f898b3d22 100644
--- a/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java
+++ b/test/src/test/java/jenkins/security/ApiTokenPropertyTest.java
@@ -21,6 +21,7 @@
 import hudson.model.User;
 import hudson.security.ACL;
 import hudson.security.ACLContext;
+import jakarta.servlet.http.HttpServletResponse;
 import java.net.HttpURLConnection;
 import java.net.URI;
 import java.net.URL;
@@ -28,7 +29,6 @@
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
-import javax.servlet.http.HttpServletResponse;
 import jenkins.model.Jenkins;
 import jenkins.security.apitoken.ApiTokenPropertyConfiguration;
 import jenkins.security.apitoken.ApiTokenStore;
diff --git a/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java b/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java
index 3a5614dedb9f..0fe9b8865d16 100644
--- a/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java
+++ b/test/src/test/java/jenkins/security/RedactSecretJsonInErrorMessageSanitizerHtmlTest.java
@@ -53,8 +53,8 @@
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.verb.POST;
 
 @Restricted(NoExternalUse.class)
@@ -121,7 +121,7 @@ public static class TestPassword implements RootAction {
 
         public JSONObject lastJsonReceived;
 
-        public void doSubmitTest(StaplerRequest req, StaplerResponse res) throws Exception {
+        public void doSubmitTest(StaplerRequest2 req, StaplerResponse2 res) throws Exception {
             lastJsonReceived = req.getSubmittedForm();
 
             res.setStatus(200);
@@ -250,7 +250,7 @@ public static class TestDescribablePage implements RootAction {
         public TestDescribable testDescribable;
 
         @POST
-        public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws Exception {
+        public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws Exception {
             Jenkins.get().getDescriptorOrDie(TestDescribable.class).newInstance(req, req.getSubmittedForm());
         }
 
@@ -276,7 +276,7 @@ public static class TestStaplerPage implements RootAction {
         public TestDescribable testDescribable;
 
         @POST
-        public void doConfigSubmit(StaplerRequest req, StaplerResponse rsp) throws Exception {
+        public void doConfigSubmit(StaplerRequest2 req, StaplerResponse2 rsp) throws Exception {
             req.bindJSON(TestDescribable.class, req.getSubmittedForm());
         }
 
diff --git a/test/src/test/java/jenkins/security/Security3030Test.java b/test/src/test/java/jenkins/security/Security3030Test.java
index 5e712bdc4e31..3363d7bb9aca 100644
--- a/test/src/test/java/jenkins/security/Security3030Test.java
+++ b/test/src/test/java/jenkins/security/Security3030Test.java
@@ -33,6 +33,7 @@
 import hudson.model.RootAction;
 import hudson.util.HttpResponses;
 import hudson.util.MultipartFormDataParser;
+import jakarta.servlet.ServletException;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -42,7 +43,6 @@
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
 import java.util.Random;
-import javax.servlet.ServletException;
 import org.apache.commons.fileupload2.core.FileUploadByteCountLimitException;
 import org.apache.commons.fileupload2.core.FileUploadException;
 import org.apache.commons.fileupload2.core.FileUploadFileCountLimitException;
@@ -56,57 +56,57 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.RequestImpl;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.verb.POST;
 
 public class Security3030Test {
-    // TODO Consider parameterizing with Stapler (RequestImpl/StaplerRequestFormAction) + Jenkins (MultipartFormDataParser/MultipartFormDataParserAction)
+    // TODO Consider parameterizing with Stapler (RequestImpl/StaplerRequest2FormAction) + Jenkins (MultipartFormDataParser/MultipartFormDataParserAction)
     @Rule
     public JenkinsRule j = new JenkinsRule();
 
     @Test
     public void fewFilesStapler() throws IOException {
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 20, 10, 1024 * 1024);
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 10, 41, 10);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 20, 10, 1024 * 1024);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 10, 41, 10);
     }
 
     @Test
     public void tooManyFilesStapler() throws Exception {
-        ServletException ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 10, 1000, 20, FileUploadFileCountLimitException.class);
+        ServletException ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 10, 1000, 20, FileUploadFileCountLimitException.class);
         assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILES"));
-        ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 1000, 10, 10, FileUploadFileCountLimitException.class);
+        ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 1000, 10, 10, FileUploadFileCountLimitException.class);
         assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILES"));
         try (FieldValue v = withStaticField(RequestImpl.class, "FILEUPLOAD_MAX_FILES", 10_000)) {
-            assertSubmissionOK(StaplerRequestFormAction.instance(), 1000, 10, 10);
-            ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 10_000, 10, 10, FileUploadFileCountLimitException.class);
+            assertSubmissionOK(StaplerRequest2FormAction.instance(), 1000, 10, 10);
+            ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 10_000, 10, 10, FileUploadFileCountLimitException.class);
             assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILES"));
         }
-        ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 10, 1000, 20, FileUploadFileCountLimitException.class);
+        ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 10, 1000, 20, FileUploadFileCountLimitException.class);
         assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILES"));
-        ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 1000, 10, 10, FileUploadFileCountLimitException.class);
+        ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 1000, 10, 10, FileUploadFileCountLimitException.class);
         assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILES"));
     }
 
     @Test
     public void tooLargeFilesStapler() throws Exception {
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024);
         try (FieldValue v = withStaticField(RequestImpl.class, "FILEUPLOAD_MAX_FILE_SIZE", 1024 * 1024)) {
-            assertSubmissionOK(StaplerRequestFormAction.instance(), 200, 100, 1024);
-            ServletException ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024, FileUploadByteCountLimitException.class);
+            assertSubmissionOK(StaplerRequest2FormAction.instance(), 200, 100, 1024);
+            ServletException ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024, FileUploadByteCountLimitException.class);
             assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_FILE_SIZE"));
         }
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024);
     }
 
     @Test
     public void tooLargeSubmissionStapler() throws Exception {
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024);
         try (FieldValue v = withStaticField(RequestImpl.class, "FILEUPLOAD_MAX_SIZE", 1024 * 1024)) {
-            assertSubmissionOK(StaplerRequestFormAction.instance(), 200, 100, 1024);
-            ServletException ex = assertSubmissionThrows(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024, FileUploadSizeException.class);
+            assertSubmissionOK(StaplerRequest2FormAction.instance(), 200, 100, 1024);
+            ServletException ex = assertSubmissionThrows(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024, FileUploadSizeException.class);
             assertThat(ex.getMessage(), containsString(RequestImpl.class.getName() + ".FILEUPLOAD_MAX_SIZE"));
         }
-        assertSubmissionOK(StaplerRequestFormAction.instance(), 1, 50, 10 * 1024 * 1024);
+        assertSubmissionOK(StaplerRequest2FormAction.instance(), 1, 50, 10 * 1024 * 1024);
     }
 
     @Test
@@ -265,7 +265,7 @@ public String getUrlName() {
         }
 
         @POST
-        public HttpResponse doSubmitMultipart(StaplerRequest req) throws FileUploadException, ServletException, IOException {
+        public HttpResponse doSubmitMultipart(StaplerRequest2 req) throws FileUploadException, ServletException, IOException {
             if (expectedWrapped == null) {
                 actualWrapped = null;
                 actual = null;
@@ -284,7 +284,7 @@ public HttpResponse doSubmitMultipart(StaplerRequest req) throws FileUploadExcep
             }
         }
 
-        private HttpResponse processMultipartAndUnwrap(StaplerRequest req) throws FileUploadException, ServletException, IOException {
+        private HttpResponse processMultipartAndUnwrap(StaplerRequest2 req) throws FileUploadException, ServletException, IOException {
             try {
                 return processMultipart(req);
             } catch (ServletException ex) {
@@ -298,7 +298,7 @@ private HttpResponse processMultipartAndUnwrap(StaplerRequest req) throws FileUp
             }
         }
 
-        protected abstract HttpResponse processMultipart(StaplerRequest req) throws ServletException, IOException;
+        protected abstract HttpResponse processMultipart(StaplerRequest2 req) throws ServletException, IOException;
 
         public void setExpectedWrapped(Class<? extends T> expectedWrapped) {
             this.expectedWrapped = expectedWrapped;
@@ -314,12 +314,12 @@ public ServletException getActual() {
     }
 
     @TestExtension
-    public static class StaplerRequestFormAction extends FileUploadAction<FileUploadException> {
-        public static StaplerRequestFormAction instance() {
-            return ExtensionList.lookupSingleton(StaplerRequestFormAction.class);
+    public static class StaplerRequest2FormAction extends FileUploadAction<FileUploadException> {
+        public static StaplerRequest2FormAction instance() {
+            return ExtensionList.lookupSingleton(StaplerRequest2FormAction.class);
         }
 
-        protected HttpResponse processMultipart(StaplerRequest req) throws ServletException, IOException {
+        protected HttpResponse processMultipart(StaplerRequest2 req) throws ServletException, IOException {
             req.getFileItem2("any-name");
             return HttpResponses.ok();
         }
@@ -331,7 +331,7 @@ public static MultipartFormDataParserAction instance() {
             return ExtensionList.lookupSingleton(MultipartFormDataParserAction.class);
         }
 
-        protected HttpResponse processMultipart(StaplerRequest req) throws ServletException {
+        protected HttpResponse processMultipart(StaplerRequest2 req) throws ServletException {
             new MultipartFormDataParser(req);
             return HttpResponses.ok();
         }
diff --git a/test/src/test/java/jenkins/security/Security3135Test.java b/test/src/test/java/jenkins/security/Security3135Test.java
index 358d4ae6c6c3..27ec5f8b0f61 100644
--- a/test/src/test/java/jenkins/security/Security3135Test.java
+++ b/test/src/test/java/jenkins/security/Security3135Test.java
@@ -14,8 +14,8 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 public class Security3135Test {
     public static final String ACTION_URL = "security3135";
@@ -72,7 +72,7 @@ public boolean isRequestMade() {
             return requestMade;
         }
 
-        public void doValidate(StaplerRequest request, StaplerResponse response) {
+        public void doValidate(StaplerRequest2 request, StaplerResponse2 response) {
             requestMade = true;
         }
     }
diff --git a/test/src/test/java/jenkins/security/SuspiciousRequestFilterTest.java b/test/src/test/java/jenkins/security/SuspiciousRequestFilterTest.java
index c0f6e95f0e57..cfc20a6bcb55 100644
--- a/test/src/test/java/jenkins/security/SuspiciousRequestFilterTest.java
+++ b/test/src/test/java/jenkins/security/SuspiciousRequestFilterTest.java
@@ -8,8 +8,8 @@
 import edu.umd.cs.findbugs.annotations.CheckForNull;
 import hudson.ExtensionList;
 import hudson.model.UnprotectedRootAction;
+import jakarta.servlet.http.HttpServletResponse;
 import java.net.URL;
-import javax.servlet.http.HttpServletResponse;
 import org.htmlunit.WebRequest;
 import org.htmlunit.WebResponse;
 import org.junit.Ignore;
diff --git a/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java b/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java
index 88e25398ff83..a5f48b49a860 100644
--- a/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java
+++ b/test/src/test/java/jenkins/security/seed/UserSeedSecurityListenerTest.java
@@ -27,7 +27,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import javax.servlet.http.HttpSession;
+import jakarta.servlet.http.HttpSession;
 import org.junit.Rule;
 import org.junit.Test;
 import org.jvnet.hudson.test.Issue;
@@ -48,7 +48,7 @@ public void authenticateSecondaryUserWhileLoggedIn_shouldNotOverwritePrimaryUser
         AuthenticationManager authenticationManager = j.jenkins.getSecurityRealm().getSecurityComponents().manager2;
         JenkinsRule.WebClient wc = j.createWebClient();
         wc.login("alice").executeOnServer(() -> {
-            HttpSession session = Stapler.getCurrentRequest().getSession();
+            HttpSession session = Stapler.getCurrentRequest2().getSession();
             String existingSeed = (String) session.getAttribute(UserSeedProperty.USER_SESSION_SEED);
             assertNotNull(existingSeed);
             authenticationManager.authenticate(new UsernamePasswordAuthenticationToken("bob", "bob"));
diff --git a/test/src/test/java/jenkins/security/stapler/CustomRoutingDecisionProviderTest.java b/test/src/test/java/jenkins/security/stapler/CustomRoutingDecisionProviderTest.java
index f808733d5d19..6ad9cd8e6eea 100644
--- a/test/src/test/java/jenkins/security/stapler/CustomRoutingDecisionProviderTest.java
+++ b/test/src/test/java/jenkins/security/stapler/CustomRoutingDecisionProviderTest.java
@@ -40,7 +40,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 
 @Issue("SECURITY-400")
@@ -99,7 +99,7 @@ public void valid() {
     }
 
     private static void replyOk() {
-        StaplerResponse resp = Stapler.getCurrentResponse();
+        StaplerResponse2 resp = Stapler.getCurrentResponse2();
         try {
             resp.getWriter().write("ok");
             resp.flushBuffer();
diff --git a/test/src/test/java/jenkins/security/stapler/DoActionFilterTest.java b/test/src/test/java/jenkins/security/stapler/DoActionFilterTest.java
index c6584f673e14..b79bed760d5b 100644
--- a/test/src/test/java/jenkins/security/stapler/DoActionFilterTest.java
+++ b/test/src/test/java/jenkins/security/stapler/DoActionFilterTest.java
@@ -4,16 +4,16 @@
 import static org.junit.Assert.assertThrows;
 import static org.junit.Assert.assertTrue;
 
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.net.URL;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import net.sf.json.JSONArray;
 import net.sf.json.JSONObject;
 import org.htmlunit.FailingHttpStatusCodeException;
@@ -36,8 +36,8 @@
 import org.kohsuke.stapler.RequestImpl;
 import org.kohsuke.stapler.ResponseImpl;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebMethod;
 import org.kohsuke.stapler.bind.JavaScriptMethod;
 import org.kohsuke.stapler.interceptor.RequirePOST;
@@ -111,17 +111,17 @@ public static class TestNewRulesOk extends AbstractUnprotectedRootAction {
          * Method signature
          */
 
-        public static void doStaticWithRequest(StaplerRequest request) { replyOk(); }
+        public static void doStaticWithRequest(StaplerRequest2 request) { replyOk(); }
 
-        public void doWithRequest(StaplerRequest request) { replyOk(); }
+        public void doWithRequest(StaplerRequest2 request) { replyOk(); }
 
         public void doWithHttpRequest(HttpServletRequest request) { replyOk(); }
 
         // the return type is not taken into consideration if it's not a HttpResponse, it will not prevent the method
         // to be considered as a web method
-        public String doWithRequestAndReturnString(StaplerRequest request) { return "ok"; }
+        public String doWithRequestAndReturnString(StaplerRequest2 request) { return "ok"; }
 
-        public void doWithResponse(StaplerResponse response) { replyOk(); }
+        public void doWithResponse(StaplerResponse2 response) { replyOk(); }
 
         public void doWithHttpResponse(HttpServletResponse response) { replyOk(); }
 
@@ -198,14 +198,14 @@ public Map<String, Object> doAnnotatedJsonResponse() {
          * Parameter annotation
          */
 
-        public void do_CallMeBecauseOfMyUnderscore(StaplerRequest request) { replyOk(); }
+        public void do_CallMeBecauseOfMyUnderscore(StaplerRequest2 request) { replyOk(); }
 
-        public void do$CallMeBecauseOfMyDollar(StaplerRequest request) { replyOk(); }
+        public void do$CallMeBecauseOfMyDollar(StaplerRequest2 request) { replyOk(); }
     }
 
     public static class HttpResponseChild implements HttpResponse {
         @Override
-        public void generateResponse(StaplerRequest req, StaplerResponse rsp, Object node) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 req, StaplerResponse2 rsp, Object node) throws IOException, ServletException {
             replyOk();
         }
     }
@@ -215,7 +215,7 @@ public abstract static class HttpResponseExceptionChild extends HttpResponses.Ht
 
     public static class ExceptionImplementingOnlyHttpResponse extends RuntimeException implements HttpResponse {
         @Override
-        public void generateResponse(StaplerRequest staplerRequest, StaplerResponse staplerResponse, Object o) throws IOException, ServletException {
+        public void generateResponse(StaplerRequest2 staplerRequest, StaplerResponse2 staplerResponse, Object o) throws IOException, ServletException {
             replyOk();
         }
     }
@@ -329,12 +329,12 @@ public void testAnnotatedMethodOk_annotatedRequirePost() throws Exception {
     public void testAnnotatedMethodOk_annotatedJavaScriptScriptMethod() throws Exception {
         webApp.setCrumbIssuer(new CrumbIssuer() {
             @Override
-            public String issueCrumb(StaplerRequest request) {
+            public String issueCrumb(StaplerRequest2 request) {
                 return "test";
             }
 
             @Override
-            public void validateCrumb(StaplerRequest request, String submittedCrumb) {
+            public void validateCrumb(StaplerRequest2 request, String submittedCrumb) {
                 // no exception thrown = validated
             }
         });
@@ -455,7 +455,7 @@ public void testSpecialCasesOk() throws Exception {
     @TestExtension
     public static class TestNewRulesNotOk extends AbstractUnprotectedRootAction {
         // do not respect the do[^a-z].* format
-        public void dontCallMeBecauseOfMyDont(StaplerRequest request) { replyOk(); }
+        public void dontCallMeBecauseOfMyDont(StaplerRequest2 request) { replyOk(); }
 
         // do not seem to be an expected web method, in case a developer has such methods,
         // addition of WebMethod annotation is sufficient
diff --git a/test/src/test/java/jenkins/security/stapler/DynamicTest.java b/test/src/test/java/jenkins/security/stapler/DynamicTest.java
index a413b1b3bd69..cee1474fface 100644
--- a/test/src/test/java/jenkins/security/stapler/DynamicTest.java
+++ b/test/src/test/java/jenkins/security/stapler/DynamicTest.java
@@ -13,7 +13,7 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @Issue("SECURITY-400")
 public class DynamicTest {
@@ -58,7 +58,7 @@ public HttpResponse doResponse2() {
             return null;
         }
 
-        public void doDynamic(StaplerRequest req) {
+        public void doDynamic(StaplerRequest2 req) {
             throw HttpResponses.errorWithoutStack(200, req.getRestOfPath());
         }
 
diff --git a/test/src/test/java/jenkins/security/stapler/PreventRoutingTest.java b/test/src/test/java/jenkins/security/stapler/PreventRoutingTest.java
index dbf2f5b16e44..7839ddaf7fa2 100644
--- a/test/src/test/java/jenkins/security/stapler/PreventRoutingTest.java
+++ b/test/src/test/java/jenkins/security/stapler/PreventRoutingTest.java
@@ -34,7 +34,7 @@
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.Stapler;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class PreventRoutingTest extends StaplerAbstractTest {
 
@@ -105,7 +105,7 @@ public Renderable getLegitRoutable2() {
     }
 
     private static void notStaplerGetter(@NonNull Object o) {
-        StaplerRequest req = Stapler.getCurrentRequest();
+        StaplerRequest2 req = Stapler.getCurrentRequest2();
         if (req != null) {
             List<Ancestor> ancestors = req.getAncestors();
             if (!ancestors.isEmpty() && ancestors.get(ancestors.size() - 1).getObject() == o) {
diff --git a/test/src/test/java/jenkins/security/stapler/Security400Test.java b/test/src/test/java/jenkins/security/stapler/Security400Test.java
index c2b64323c65e..3ce8826dea97 100644
--- a/test/src/test/java/jenkins/security/stapler/Security400Test.java
+++ b/test/src/test/java/jenkins/security/stapler/Security400Test.java
@@ -84,7 +84,7 @@ public class Security400Test {
 
     @Before
     public void prepareFilterListener() {
-        WebApp webApp = WebApp.get(j.jenkins.servletContext);
+        WebApp webApp = WebApp.get(j.jenkins.getServletContext());
         webApp.setFilteredDoActionTriggerListener((f, req, rsp, node) -> {
             filteredDoActionTriggered = true;
             return false;
diff --git a/test/src/test/java/jenkins/security/stapler/StaplerAbstractTest.java b/test/src/test/java/jenkins/security/stapler/StaplerAbstractTest.java
index b36b0de579be..a9f8cb2df164 100644
--- a/test/src/test/java/jenkins/security/stapler/StaplerAbstractTest.java
+++ b/test/src/test/java/jenkins/security/stapler/StaplerAbstractTest.java
@@ -46,7 +46,7 @@
 import org.junit.ClassRule;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.WebApp;
 import org.kohsuke.stapler.WebMethod;
 
@@ -66,7 +66,7 @@ public void setUp() throws Exception {
         j = rule;
         j.jenkins.setCrumbIssuer(null);
 
-        this.webApp = (WebApp) j.jenkins.servletContext.getAttribute(WebApp.class.getName());
+        this.webApp = (WebApp) j.jenkins.getServletContext().getAttribute(WebApp.class.getName());
 
         webApp.setFilteredGetterTriggerListener((f, req, rst, node, expression) -> {
             filteredGetMethodTriggered = true;
@@ -134,7 +134,7 @@ public void doIndex() {
     //================================= utility methods =================================
 
     protected static void replyOk() {
-        StaplerResponse resp = Stapler.getCurrentResponse();
+        StaplerResponse2 resp = Stapler.getCurrentResponse2();
         try {
             resp.getWriter().write("ok");
             resp.flushBuffer();
diff --git a/test/src/test/java/jenkins/security/stapler/StaplerDispatchValidatorTest.java b/test/src/test/java/jenkins/security/stapler/StaplerDispatchValidatorTest.java
index 0483b2825e43..2ebf2cbb5c1f 100644
--- a/test/src/test/java/jenkins/security/stapler/StaplerDispatchValidatorTest.java
+++ b/test/src/test/java/jenkins/security/stapler/StaplerDispatchValidatorTest.java
@@ -47,7 +47,7 @@ public class StaplerDispatchValidatorTest {
 
     @Before
     public void setUp() throws Exception {
-        StaplerDispatchValidator validator = StaplerDispatchValidator.getInstance(j.jenkins.servletContext);
+        StaplerDispatchValidator validator = StaplerDispatchValidator.getInstance(j.jenkins.getServletContext());
         try (InputStream whitelist = getClass().getResourceAsStream("StaplerDispatchValidatorTest/whitelist.txt")) {
             validator.loadWhitelist(whitelist);
         }
diff --git a/test/src/test/java/jenkins/security/stapler/StaplerRoutableActionTest.java b/test/src/test/java/jenkins/security/stapler/StaplerRoutableActionTest.java
index 02acda598ccc..15b6965ce9b2 100644
--- a/test/src/test/java/jenkins/security/stapler/StaplerRoutableActionTest.java
+++ b/test/src/test/java/jenkins/security/stapler/StaplerRoutableActionTest.java
@@ -6,7 +6,7 @@
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponses;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.WebMethod;
 
 @Issue("SECURITY-400")
@@ -29,7 +29,7 @@ public void doWebMethod3() throws HttpResponses.HttpResponseException {
             replyOk();
         }
 
-        public void doWebMethod4(StaplerRequest request) {
+        public void doWebMethod4(StaplerRequest2 request) {
             replyOk();
         }
 
diff --git a/test/src/test/java/jenkins/security/stapler/StaticRoutingDecisionProviderTest.java b/test/src/test/java/jenkins/security/stapler/StaticRoutingDecisionProviderTest.java
index 9e849a227864..9fed43b27781 100644
--- a/test/src/test/java/jenkins/security/stapler/StaticRoutingDecisionProviderTest.java
+++ b/test/src/test/java/jenkins/security/stapler/StaticRoutingDecisionProviderTest.java
@@ -41,7 +41,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.WebMethod;
 
 @Issue("SECURITY-400")
@@ -224,30 +224,30 @@ public static class ActionWithWhitelist extends AbstractUnprotectedRootAction {
             return "do-action";
         }
 
-        public static String DO_ACTION_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doAction org.kohsuke.stapler.StaplerRequest";
+        public static String DO_ACTION_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doAction org.kohsuke.stapler.StaplerRequest2";
 
-        public void doAction(StaplerRequest request) {
+        public void doAction(StaplerRequest2 request) {
             replyOk();
         }
 
-        public static String DO_ACTION_STAPLER_ROUTABLE_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithStaplerDispatchable org.kohsuke.stapler.StaplerRequest";
+        public static String DO_ACTION_STAPLER_ROUTABLE_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithStaplerDispatchable org.kohsuke.stapler.StaplerRequest2";
 
         @StaplerDispatchable
-        public void doActionWithStaplerDispatchable(StaplerRequest request) {
+        public void doActionWithStaplerDispatchable(StaplerRequest2 request) {
             replyOk();
         }
 
-        public static String DO_ACTION_STAPLER_NONROUTABLE_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithStaplerNotDispatchable org.kohsuke.stapler.StaplerRequest";
+        public static String DO_ACTION_STAPLER_NONROUTABLE_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithStaplerNotDispatchable org.kohsuke.stapler.StaplerRequest2";
 
         @StaplerNotDispatchable
-        public void doActionWithStaplerNotDispatchable(StaplerRequest request) {
+        public void doActionWithStaplerNotDispatchable(StaplerRequest2 request) {
             replyOk();
         }
 
-        public static String DO_ACTION_STAPLER_WEBMETHOD_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithWebMethod org.kohsuke.stapler.StaplerRequest";
+        public static String DO_ACTION_STAPLER_WEBMETHOD_SIGNATURE = "method jenkins.security.stapler.StaticRoutingDecisionProviderTest$ActionWithWhitelist doActionWithWebMethod org.kohsuke.stapler.StaplerRequest2";
 
         @WebMethod(name = "actionWithWebMethod")
-        public void doActionWithWebMethod(StaplerRequest request) {
+        public void doActionWithWebMethod(StaplerRequest2 request) {
             replyOk();
         }
     }
diff --git a/test/src/test/java/jenkins/security/stapler/TypedFilterTest.java b/test/src/test/java/jenkins/security/stapler/TypedFilterTest.java
index fdebee225bad..ac0ea1bf155d 100644
--- a/test/src/test/java/jenkins/security/stapler/TypedFilterTest.java
+++ b/test/src/test/java/jenkins/security/stapler/TypedFilterTest.java
@@ -4,7 +4,7 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.StaplerProxy;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 @Issue("SECURITY-400")
 public class TypedFilterTest extends StaplerAbstractTest {
@@ -48,7 +48,7 @@ public void getTarget_withArg_isNotRoutableWithStaplerNotDispatchable() throws E
 
     @TestExtension
     public static class GetTarget4 extends AbstractUnprotectedRootAction {
-        public Renderable getTarget(StaplerRequest req) {
+        public Renderable getTarget(StaplerRequest2 req) {
             return new Renderable();
         }
     }
@@ -98,7 +98,7 @@ public void getStaplerFallback_withArg_isNotRoutableWithStaplerNotDispatchable()
 
     @TestExtension
     public static class GetStaplerFallback4 extends AbstractUnprotectedRootAction {
-        public Renderable getStaplerFallback(StaplerRequest req) {
+        public Renderable getStaplerFallback(StaplerRequest2 req) {
             return new Renderable();
         }
     }
@@ -203,7 +203,7 @@ public void getDynamic_withArgStartingWithString_isRoutable() throws Exception {
 
     @TestExtension
     public static class GetDynamic3 extends AbstractUnprotectedRootAction {
-        public Renderable getDynamic(StaplerRequest req, String someArgs) {
+        public Renderable getDynamic(StaplerRequest2 req, String someArgs) {
             return new Renderable();
         }
     }
@@ -216,7 +216,7 @@ public void getDynamic_withArgNotStartingWithString_isNotRoutable() throws Excep
 
     @TestExtension
     public static class GetDynamic4 extends AbstractUnprotectedRootAction {
-        public Renderable getDynamic(StaplerRequest req) {
+        public Renderable getDynamic(StaplerRequest2 req) {
             return new Renderable();
         }
     }
diff --git a/test/src/test/java/jenkins/telemetry/TelemetryTest.java b/test/src/test/java/jenkins/telemetry/TelemetryTest.java
index f465fdf2fd8a..701ffa7e4d0e 100644
--- a/test/src/test/java/jenkins/telemetry/TelemetryTest.java
+++ b/test/src/test/java/jenkins/telemetry/TelemetryTest.java
@@ -15,6 +15,10 @@
 import hudson.ExtensionList;
 import hudson.model.UnprotectedRootAction;
 import hudson.security.csrf.CrumbExclusion;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.StringWriter;
 import java.nio.charset.StandardCharsets;
@@ -26,10 +30,6 @@
 import java.util.concurrent.TimeUnit;
 import java.util.logging.Level;
 import java.util.regex.Pattern;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import net.sf.json.JSONObject;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.io.IOUtils;
@@ -39,8 +39,8 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 
 public class TelemetryTest {
     @Rule
@@ -304,7 +304,7 @@ public boolean process(HttpServletRequest request, HttpServletResponse response,
 
     @TestExtension
     public static class TelemetryReceiver implements UnprotectedRootAction {
-        public void doEvents(StaplerRequest request, StaplerResponse response) throws IOException {
+        public void doEvents(StaplerRequest2 request, StaplerResponse2 response) throws IOException {
             StringWriter sw = new StringWriter();
             IOUtils.copy(request.getInputStream(), sw, StandardCharsets.UTF_8);
             JSONObject json = JSONObject.fromObject(sw.toString());
diff --git a/test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java b/test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
index e39d906ff51b..461588cd3480 100644
--- a/test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
+++ b/test/src/test/java/jenkins/util/FullDuplexHttpServiceTest.java
@@ -30,6 +30,10 @@
 import hudson.model.InvisibleAction;
 import hudson.model.RootAction;
 import hudson.security.csrf.CrumbExclusion;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -38,17 +42,13 @@
 import java.util.UUID;
 import java.util.logging.Level;
 import java.util.logging.Logger;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 import org.junit.Rule;
 import org.junit.Test;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.LoggerRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class FullDuplexHttpServiceTest {
 
@@ -83,7 +83,7 @@ public String getUrlName() {
         public HttpResponse doIndex() {
             return new FullDuplexHttpService.Response(duplexServices) {
                 @Override
-                protected FullDuplexHttpService createService(StaplerRequest req, UUID uuid) throws IOException, InterruptedException {
+                protected FullDuplexHttpService createService(StaplerRequest2 req, UUID uuid) throws IOException, InterruptedException {
                     return new FullDuplexHttpService(uuid) {
                         @Override
                         protected void run(InputStream upload, OutputStream download) throws IOException, InterruptedException {
diff --git a/test/src/test/java/jenkins/util/SystemPropertiesTest.java b/test/src/test/java/jenkins/util/SystemPropertiesTest.java
index d0b498f88e57..d29655b765ac 100644
--- a/test/src/test/java/jenkins/util/SystemPropertiesTest.java
+++ b/test/src/test/java/jenkins/util/SystemPropertiesTest.java
@@ -28,8 +28,8 @@
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.nullValue;
 
-import javax.servlet.ServletContextEvent;
-import org.eclipse.jetty.ee8.webapp.WebAppContext;
+import jakarta.servlet.ServletContextEvent;
+import org.eclipse.jetty.ee9.webapp.WebAppContext;
 import org.hamcrest.Matchers;
 import org.junit.After;
 import org.junit.Assume;
@@ -49,7 +49,7 @@ public class SystemPropertiesTest {
 
     @Before
     public void setUp() {
-        new SystemProperties.Listener().contextInitialized(new ServletContextEvent(j.jenkins.servletContext));
+        new SystemProperties.Listener().contextInitialized(new ServletContextEvent(j.jenkins.getServletContext()));
     }
 
     @After
@@ -103,7 +103,7 @@ public void shouldReturnWebAppPropertyIfSystemPropertyNotSetAndDefaultIsSet() th
      * @param value value of the property
      */
     protected void setWebAppInitParameter(String property, String value) {
-        Assume.assumeThat(j.jenkins.servletContext, Matchers.instanceOf(WebAppContext.Context.class));
-        ((WebAppContext.Context) j.jenkins.servletContext).getContextHandler().getInitParams().put(property, value);
+        Assume.assumeThat(j.jenkins.getServletContext(), Matchers.instanceOf(WebAppContext.Context.class));
+        ((WebAppContext.Context) j.jenkins.getServletContext()).getContextHandler().getInitParams().put(property, value);
     }
 }
diff --git a/test/src/test/java/lib/form/AdvancedButtonTest.java b/test/src/test/java/lib/form/AdvancedButtonTest.java
index 9d19a00c05f0..9b41fd1df8f4 100644
--- a/test/src/test/java/lib/form/AdvancedButtonTest.java
+++ b/test/src/test/java/lib/form/AdvancedButtonTest.java
@@ -16,7 +16,7 @@
 import org.jvnet.hudson.test.Issue;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  *
@@ -54,7 +54,7 @@ public String getUrlName() {
             return "self";
         }
 
-        public FormValidation doSubmitNestedOptionalBlock(StaplerRequest req) throws Exception {
+        public FormValidation doSubmitNestedOptionalBlock(StaplerRequest2 req) throws Exception {
             JSONObject f = req.getSubmittedForm();
             assertEquals("avalue", f.getString("a"));
             assertEquals("bvalue", f.getString("b"));
diff --git a/test/src/test/java/lib/form/BooleanRadioTest.java b/test/src/test/java/lib/form/BooleanRadioTest.java
index 185acee61d96..072937f157a2 100644
--- a/test/src/test/java/lib/form/BooleanRadioTest.java
+++ b/test/src/test/java/lib/form/BooleanRadioTest.java
@@ -16,7 +16,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class BooleanRadioTest {
 
@@ -46,7 +46,7 @@ public static final class DescriptorImpl extends Descriptor<BooleanRadioTestDesc
 
     @TestExtension
     public static final class RootActionImpl extends InvisibleAction implements RootAction {
-        public FormValidation doSubmitTest1(StaplerRequest req) throws Exception {
+        public FormValidation doSubmitTest1(StaplerRequest2 req) throws Exception {
             JSONObject f = req.getSubmittedForm();
             System.out.println(f);
             BooleanRadioTestDescribable r = req.bindJSON(BooleanRadioTestDescribable.class, f);
diff --git a/test/src/test/java/lib/form/DropdownListTest.java b/test/src/test/java/lib/form/DropdownListTest.java
index 6ae425d3629c..e8ec382de4f0 100644
--- a/test/src/test/java/lib/form/DropdownListTest.java
+++ b/test/src/test/java/lib/form/DropdownListTest.java
@@ -10,7 +10,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -33,7 +33,7 @@ public String getUrlName() {
             return "self";
         }
 
-        public FormValidation doSubmitTest1(StaplerRequest req) throws Exception {
+        public FormValidation doSubmitTest1(StaplerRequest2 req) throws Exception {
             JSONObject f = req.getSubmittedForm();
             System.out.println(f);
             return FormValidation.ok();
diff --git a/test/src/test/java/lib/form/EnumSetTest.java b/test/src/test/java/lib/form/EnumSetTest.java
index 2b3289254513..c63a9341c13b 100644
--- a/test/src/test/java/lib/form/EnumSetTest.java
+++ b/test/src/test/java/lib/form/EnumSetTest.java
@@ -15,7 +15,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -46,7 +46,7 @@ public static final class DescriptorImpl extends Descriptor<EnumSetTestDescribab
 
     @TestExtension
     public static final class RootActionImpl extends InvisibleAction implements RootAction {
-        public FormValidation doSubmitTest1(StaplerRequest req) throws Exception {
+        public FormValidation doSubmitTest1(StaplerRequest2 req) throws Exception {
             JSONObject f = req.getSubmittedForm();
             System.out.println(f);
             EnumSetTestDescribable r = req.bindJSON(EnumSetTestDescribable.class, f);
diff --git a/test/src/test/java/lib/form/EnumTest.java b/test/src/test/java/lib/form/EnumTest.java
index 5f37deecafe5..92fecd3c300f 100644
--- a/test/src/test/java/lib/form/EnumTest.java
+++ b/test/src/test/java/lib/form/EnumTest.java
@@ -17,7 +17,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 public class EnumTest {
     @Rule
@@ -61,7 +61,7 @@ public static class Form extends InvisibleAction implements RootAction, Describa
         public BallColor enum1 = BallColor.YELLOW;
         public BallColor enum2 = null;
 
-        public void doSubmitForm(StaplerRequest req) throws Exception {
+        public void doSubmitForm(StaplerRequest2 req) throws Exception {
             JSONObject json = req.getSubmittedForm();
             System.out.println(json);
         }
diff --git a/test/src/test/java/lib/form/ExpandableTextboxTest.java b/test/src/test/java/lib/form/ExpandableTextboxTest.java
index 5e40ea263b30..52dda457594f 100644
--- a/test/src/test/java/lib/form/ExpandableTextboxTest.java
+++ b/test/src/test/java/lib/form/ExpandableTextboxTest.java
@@ -53,7 +53,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.WebMethod;
 import org.w3c.dom.NodeList;
 
@@ -147,7 +147,7 @@ public String getUrlName() {
         }
 
         @WebMethod(name = "submit")
-        public HttpResponse doSubmit(StaplerRequest request) {
+        public HttpResponse doSubmit(StaplerRequest2 request) {
             return HttpResponses.plainText("method:" + request.getMethod());
         }
     }
diff --git a/test/src/test/java/lib/form/NameRefTest.java b/test/src/test/java/lib/form/NameRefTest.java
index b343d6e46fde..b1980745931b 100644
--- a/test/src/test/java/lib/form/NameRefTest.java
+++ b/test/src/test/java/lib/form/NameRefTest.java
@@ -33,7 +33,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.kohsuke.stapler.HttpResponse;
 import org.kohsuke.stapler.HttpResponses;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Tests the handling of @nameRef in the form tree.
@@ -50,7 +50,7 @@ public class NameRefTest {
 
     public static class JenkinsRuleWithJelly extends JenkinsRule {
 
-        public HttpResponse doSubmitTest1(StaplerRequest req) throws Exception {
+        public HttpResponse doSubmitTest1(StaplerRequest2 req) throws Exception {
             JSONObject f = req.getSubmittedForm();
             f.remove("Submit");
             System.out.println(f);
diff --git a/test/src/test/java/lib/form/PasswordTest.java b/test/src/test/java/lib/form/PasswordTest.java
index e71fb93f8e8b..facb1d7418df 100644
--- a/test/src/test/java/lib/form/PasswordTest.java
+++ b/test/src/test/java/lib/form/PasswordTest.java
@@ -84,7 +84,7 @@
 import org.kohsuke.stapler.DataBoundSetter;
 import org.kohsuke.stapler.QueryParameter;
 import org.kohsuke.stapler.Stapler;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.springframework.security.core.Authentication;
 
 public class PasswordTest {
@@ -244,7 +244,7 @@ public static class DescriptorImpl extends JobPropertyDescriptor {
             static String checkedSecret;
 
             public FormValidation doCheckSecret(@QueryParameter String value) {
-                StaplerRequest req = Stapler.getCurrentRequest();
+                StaplerRequest2 req = Stapler.getCurrentRequest2();
                 incomingURL = req.getRequestURIWithQueryString();
                 System.err.println("processing " + incomingURL + " via " + req.getMethod() + ": " + value);
                 checkedSecret = value;
diff --git a/test/src/test/java/lib/form/RepeatableTest.java b/test/src/test/java/lib/form/RepeatableTest.java
index 56dd22430811..996132434cae 100644
--- a/test/src/test/java/lib/form/RepeatableTest.java
+++ b/test/src/test/java/lib/form/RepeatableTest.java
@@ -55,7 +55,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Alan.Harder@sun.com
@@ -658,7 +658,7 @@ public DescriptorExtensionList<Fruit, Descriptor<Fruit>> getFruitDescriptors() {
             return Jenkins.get().getDescriptorList(Fruit.class);
         }
 
-        public void doSubmitTest(StaplerRequest req) throws Exception {
+        public void doSubmitTest(StaplerRequest2 req) throws Exception {
             formData = req.getSubmittedForm();
             if (bindClass != null) {
                 bindResult = req.bindJSONToList(bindClass, formData.get("items"));
diff --git a/test/src/test/java/lib/form/RowSetTest.java b/test/src/test/java/lib/form/RowSetTest.java
index cb24e173038a..b775b24d77e2 100644
--- a/test/src/test/java/lib/form/RowSetTest.java
+++ b/test/src/test/java/lib/form/RowSetTest.java
@@ -11,7 +11,7 @@
 import org.junit.Test;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * @author Kohsuke Kawaguchi
@@ -28,7 +28,7 @@ public void json() throws Exception {
 
     @TestExtension
     public static class Subject extends InvisibleAction implements RootAction {
-        public void doSubmitTest1(StaplerRequest req) throws Exception {
+        public void doSubmitTest1(StaplerRequest2 req) throws Exception {
             JSONObject json = req.getSubmittedForm();
             json.remove(CrumbIssuer.DEFAULT_CRUMB_NAME);
             json.remove("Submit");
diff --git a/test/src/test/java/lib/form/RowVisibilityGroupTest.java b/test/src/test/java/lib/form/RowVisibilityGroupTest.java
index 6b090cc28dbe..6508193392c3 100644
--- a/test/src/test/java/lib/form/RowVisibilityGroupTest.java
+++ b/test/src/test/java/lib/form/RowVisibilityGroupTest.java
@@ -25,7 +25,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.DataBoundConstructor;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  * Tests the 'rowvg-start' and 'rowvg-end' CSS attributes and their effects.
@@ -162,7 +162,7 @@ public static final class RootActionImpl extends InvisibleAction implements Desc
         public Drink drink;
         private Beer beer;
 
-        public void doSubmitTest2(StaplerRequest req) throws Exception {
+        public void doSubmitTest2(StaplerRequest2 req) throws Exception {
             JSONObject json = req.getSubmittedForm();
             System.out.println(json);
             beer = (Beer) req.bindJSON(Drink.class, json.getJSONObject("drink"));
diff --git a/test/src/test/java/lib/form/ValidateButtonTest.java b/test/src/test/java/lib/form/ValidateButtonTest.java
index da9bc286be14..675795a6e323 100644
--- a/test/src/test/java/lib/form/ValidateButtonTest.java
+++ b/test/src/test/java/lib/form/ValidateButtonTest.java
@@ -56,7 +56,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.QueryParameter;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 
 /**
  *
@@ -214,7 +214,7 @@ public static final class DescriptorImpl extends Descriptor<NoInjectionArePossib
             public String paramMethod = "validateInjection";
             public String paramWith = null;
 
-            public void doValidateInjection(StaplerRequest request) {
+            public void doValidateInjection(StaplerRequest2 request) {
                 wasCalled = true;
             }
         }
@@ -267,7 +267,7 @@ public static class ValidateProperty extends JobProperty<Job<?, ?>> {
         public static class DescriptorImpl extends JobPropertyDescriptor {
             public boolean called = false;
 
-            public void doSomething(StaplerRequest req) {
+            public void doSomething(StaplerRequest2 req) {
                 called = true;
             }
         }
diff --git a/test/src/test/java/lib/layout/ConfirmationLinkTest.java b/test/src/test/java/lib/layout/ConfirmationLinkTest.java
index 42a52cc3c6e8..dca6f81f73f2 100644
--- a/test/src/test/java/lib/layout/ConfirmationLinkTest.java
+++ b/test/src/test/java/lib/layout/ConfirmationLinkTest.java
@@ -46,7 +46,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.WebMethod;
 
 public class ConfirmationLinkTest {
@@ -202,7 +202,7 @@ public String getUrlName() {
         }
 
         @WebMethod(name = "submit")
-        public HttpResponse doSubmit(StaplerRequest request) {
+        public HttpResponse doSubmit(StaplerRequest2 request) {
             return HttpResponses.plainText("method:" + request.getMethod());
         }
     }
diff --git a/test/src/test/java/lib/layout/StopButtonTest.java b/test/src/test/java/lib/layout/StopButtonTest.java
index e29aa99c7198..79c0d0ee68b5 100644
--- a/test/src/test/java/lib/layout/StopButtonTest.java
+++ b/test/src/test/java/lib/layout/StopButtonTest.java
@@ -42,7 +42,7 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.TestExtension;
 import org.kohsuke.stapler.HttpResponse;
-import org.kohsuke.stapler.StaplerRequest;
+import org.kohsuke.stapler.StaplerRequest2;
 import org.kohsuke.stapler.WebMethod;
 
 public class StopButtonTest {
@@ -143,7 +143,7 @@ public static class TestRootAction implements UnprotectedRootAction {
         }
 
         @WebMethod(name = "submit")
-        public HttpResponse doSubmit(StaplerRequest request) {
+        public HttpResponse doSubmit(StaplerRequest2 request) {
             return HttpResponses.plainText("method:" + request.getMethod());
         }
     }
diff --git a/test/src/test/java/lib/layout/TaskTest.java b/test/src/test/java/lib/layout/TaskTest.java
index 4e6918d2be0a..9dfac80a1c4a 100644
--- a/test/src/test/java/lib/layout/TaskTest.java
+++ b/test/src/test/java/lib/layout/TaskTest.java
@@ -27,8 +27,8 @@
 import static org.junit.Assert.assertTrue;
 
 import hudson.model.UnprotectedRootAction;
+import jakarta.servlet.ServletException;
 import java.io.IOException;
-import javax.servlet.ServletException;
 import org.htmlunit.html.HtmlElementUtil;
 import org.htmlunit.html.HtmlPage;
 import org.junit.Rule;
@@ -36,8 +36,8 @@
 import org.jvnet.hudson.test.JenkinsRule;
 import org.jvnet.hudson.test.JenkinsRule.WebClient;
 import org.jvnet.hudson.test.TestExtension;
-import org.kohsuke.stapler.StaplerRequest;
-import org.kohsuke.stapler.StaplerResponse;
+import org.kohsuke.stapler.StaplerRequest2;
+import org.kohsuke.stapler.StaplerResponse2;
 import org.kohsuke.stapler.interceptor.RequirePOST;
 
 public class TaskTest {
@@ -56,7 +56,7 @@ public class TaskTest {
     public static class MockAction implements UnprotectedRootAction {
         private boolean called = false;
 
-        @RequirePOST public void doPost(StaplerRequest req, StaplerResponse rsp) throws ServletException, IOException {
+        @RequirePOST public void doPost(StaplerRequest2 req, StaplerResponse2 rsp) throws ServletException, IOException {
             if (called) throw new AssertionError();
             called = true;
             rsp.forwardToPreviousPage(req);
diff --git a/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java b/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java
index cf8b1eee4fcc..2e9e9c1c793b 100644
--- a/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java
+++ b/test/src/test/java/org/kohsuke/stapler/MockStaplerRequestBuilder.java
@@ -25,16 +25,16 @@
 package org.kohsuke.stapler;
 
 import edu.umd.cs.findbugs.annotations.NonNull;
+import jakarta.servlet.http.HttpServletRequest;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
 import org.jvnet.hudson.test.JenkinsRule;
 import org.mockito.Mockito;
 
 /**
- * Mocked version of {@link StaplerRequest}.
+ * Mocked version of {@link StaplerRequest2}.
  * @author Oleg Nenashev
  */
 public class MockStaplerRequestBuilder {
@@ -66,7 +66,7 @@ public MockStaplerRequestBuilder withAncestor(AncestorImpl ancestor) {
         return this;
     }
 
-    public StaplerRequest build() {
+    public StaplerRequest2 build() {
         HttpServletRequest rawRequest = Mockito.mock(HttpServletRequest.class);
         return new RequestImpl(stapler != null ? stapler : new Stapler(), rawRequest, ancestors, tokens);
     }
diff --git a/test/src/test/java/org/kohsuke/stapler/Security1097Test.java b/test/src/test/java/org/kohsuke/stapler/Security1097Test.java
index 650304e5bc40..28e63811e712 100644
--- a/test/src/test/java/org/kohsuke/stapler/Security1097Test.java
+++ b/test/src/test/java/org/kohsuke/stapler/Security1097Test.java
@@ -6,11 +6,11 @@
 import hudson.Extension;
 import hudson.model.InvisibleAction;
 import hudson.model.RootAction;
+import jakarta.servlet.ServletException;
 import java.lang.reflect.Field;
 import java.net.HttpURLConnection;
 import java.util.Arrays;
 import java.util.List;
-import javax.servlet.ServletException;
 import net.sf.json.JSONObject;
 import org.htmlunit.FailingHttpStatusCodeException;
 import org.htmlunit.html.HtmlPage;
@@ -74,7 +74,7 @@ public String getUrlName() {
         }
 
         /* Deliberate CSRF vulnerability */
-        public void doConfigSubmit1(StaplerRequest req) throws ServletException {
+        public void doConfigSubmit1(StaplerRequest2 req) throws ServletException {
             req.getSubmittedForm();
         }
 
diff --git a/war/pom.xml b/war/pom.xml
index e6b4bf8251b7..e9ba3dfc6f9e 100644
--- a/war/pom.xml
+++ b/war/pom.xml
@@ -87,12 +87,7 @@ THE SOFTWARE.
     </dependency>
     <dependency>
       <groupId>org.jenkins-ci.main</groupId>
-      <artifactId>websocket-jetty10</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.jenkins-ci.main</groupId>
-      <artifactId>websocket-jetty12-ee8</artifactId>
+      <artifactId>websocket-jetty12-ee9</artifactId>
       <version>${project.version}</version>
     </dependency>
     <dependency>
@@ -161,13 +156,22 @@ THE SOFTWARE.
                     <exclude>org.jenkins-ci:commons-jelly</exclude>
                     <exclude>org.jenkins-ci.main:cli</exclude>
                     <exclude>org.jenkins-ci.main:jenkins-core</exclude>
-                    <exclude>org.jenkins-ci.main:websocket-jetty10</exclude>
-                    <exclude>org.jenkins-ci.main:websocket-jetty12-ee8</exclude>
+                    <exclude>org.jenkins-ci.main:websocket-jetty12-ee9</exclude>
                     <exclude>org.jenkins-ci.main:websocket-spi</exclude>
+                    <exclude>org.jvnet.hudson:commons-jelly-tags-define</exclude>
                     <exclude>org.jvnet.winp:winp</exclude>
                     <exclude>org.kohsuke.stapler:stapler</exclude>
                     <exclude>org.kohsuke.stapler:stapler-groovy</exclude>
                     <exclude>org.kohsuke.stapler:stapler-jelly</exclude>
+                    <exclude>org.springframework.security:spring-security-core</exclude>
+                    <exclude>org.springframework.security:spring-security-crypto</exclude>
+                    <exclude>org.springframework.security:spring-security-web</exclude>
+                    <exclude>org.springframework:spring-aop</exclude>
+                    <exclude>org.springframework:spring-beans</exclude>
+                    <exclude>org.springframework:spring-context</exclude>
+                    <exclude>org.springframework:spring-core</exclude>
+                    <exclude>org.springframework:spring-expression</exclude>
+                    <exclude>org.springframework:spring-web</exclude>
                   </excludes>
                 </enforceBytecodeVersion>
               </rules>
@@ -636,8 +640,8 @@ THE SOFTWARE.
         </configuration>
       </plugin>
       <plugin>
-        <groupId>org.eclipse.jetty.ee8</groupId>
-        <artifactId>jetty-ee8-maven-plugin</artifactId>
+        <groupId>org.eclipse.jetty.ee9</groupId>
+        <artifactId>jetty-ee9-maven-plugin</artifactId>
         <version>12.0.12</version>
         <configuration>
           <!--
diff --git a/websocket/jetty10/pom.xml b/websocket/jetty10/pom.xml
deleted file mode 100644
index 5147b02b81d6..000000000000
--- a/websocket/jetty10/pom.xml
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
-The MIT License
-
-Copyright (c) 2019, CloudBees, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-
-  <parent>
-    <groupId>org.jenkins-ci.main</groupId>
-    <artifactId>jenkins-parent</artifactId>
-    <version>${revision}${changelist}</version>
-    <relativePath>../..</relativePath>
-  </parent>
-
-  <artifactId>websocket-jetty10</artifactId>
-  <name>Jetty 10 implementation for WebSocket</name>
-  <description>An implementation of the WebSocket handler that works with Jetty 10.</description>
-
-  <dependencyManagement>
-    <dependencies>
-      <dependency>
-        <groupId>org.jenkins-ci.main</groupId>
-        <artifactId>jenkins-bom</artifactId>
-        <version>${project.version}</version>
-        <type>pom</type>
-        <scope>import</scope>
-      </dependency>
-    </dependencies>
-  </dependencyManagement>
-
-  <dependencies>
-    <dependency>
-      <groupId>org.jenkins-ci</groupId>
-      <artifactId>winstone</artifactId>
-      <version>6.21</version>
-      <optional>true</optional>
-    </dependency>
-    <dependency>
-      <groupId>org.jenkins-ci.main</groupId>
-      <artifactId>websocket-spi</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.kohsuke</groupId>
-      <artifactId>access-modifier-annotation</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.kohsuke.metainf-services</groupId>
-      <artifactId>metainf-services</artifactId>
-      <optional>true</optional>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-javadoc-plugin</artifactId>
-        <configuration>
-          <skip>true</skip>
-        </configuration>
-      </plugin>
-    </plugins>
-  </build>
-</project>
diff --git a/websocket/jetty10/src/main/java/jenkins/websocket/Jetty10Provider.java b/websocket/jetty10/src/main/java/jenkins/websocket/Jetty10Provider.java
deleted file mode 100644
index b5243e627f52..000000000000
--- a/websocket/jetty10/src/main/java/jenkins/websocket/Jetty10Provider.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * The MIT License
- *
- * Copyright 2022 CloudBees, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-
-package jenkins.websocket;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.time.Duration;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.Future;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.websocket.api.Session;
-import org.eclipse.jetty.websocket.api.WebSocketListener;
-import org.eclipse.jetty.websocket.api.WriteCallback;
-import org.eclipse.jetty.websocket.server.JettyServerUpgradeRequest;
-import org.eclipse.jetty.websocket.server.JettyServerUpgradeResponse;
-import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
-import org.kohsuke.MetaInfServices;
-import org.kohsuke.accmod.Restricted;
-import org.kohsuke.accmod.restrictions.NoExternalUse;
-
-@Restricted(NoExternalUse.class)
-@MetaInfServices(Provider.class)
-public class Jetty10Provider implements Provider {
-
-    /**
-     * Number of seconds a WebsocketConnection may stay idle until it expires.
-     * Zero to disable.
-     * This value must be higher than the <code>jenkins.websocket.pingInterval</code>.
-     * Per <a href=https://www.eclipse.org/jetty/documentation/jetty-10/programming-guide/index.html#pg-websocket-session-ping>Jetty 10 documentation</a>
-     * a ping mechanism should keep the websocket active. Therefore, the idle timeout must be higher than the ping
-     * interval to avoid timeout issues.
-     */
-    private static long IDLE_TIMEOUT_SECONDS = Long.getLong("jenkins.websocket.idleTimeout", 60L);
-
-    private static final String ATTR_LISTENER = Jetty10Provider.class.getName() + ".listener";
-
-    private boolean initialized = false;
-
-    public Jetty10Provider() {
-        JettyWebSocketServerContainer.class.hashCode();
-    }
-
-    private void init(HttpServletRequest req) {
-        if (!initialized) {
-            JettyWebSocketServerContainer.getContainer(req.getServletContext()).setIdleTimeout(Duration.ofSeconds(IDLE_TIMEOUT_SECONDS));
-            initialized = true;
-        }
-    }
-
-    @Override
-    public Handler handle(HttpServletRequest req, HttpServletResponse rsp, Listener listener) throws Exception {
-        init(req);
-        req.setAttribute(ATTR_LISTENER, listener);
-        // TODO Jetty 10 has no obvious equivalent to WebSocketServerFactory.isUpgradeRequest; RFC6455Negotiation?
-        if (!"websocket".equalsIgnoreCase(req.getHeader("Upgrade"))) {
-            rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "only WS connections accepted here");
-            return null;
-        }
-        if (!JettyWebSocketServerContainer.getContainer(req.getServletContext()).upgrade(Jetty10Provider::createWebSocket, req, rsp)) {
-            rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "did not manage to upgrade");
-            return null;
-        }
-        return new Handler() {
-            @Override
-            public Future<Void> sendBinary(ByteBuffer data) throws IOException {
-                CompletableFuture<Void> f = new CompletableFuture<>();
-                session().getRemote().sendBytes(data, new WriteCallbackImpl(f));
-                return f;
-            }
-
-            @Override
-            public void sendBinary(ByteBuffer partialByte, boolean isLast) throws IOException {
-                session().getRemote().sendPartialBytes(partialByte, isLast);
-            }
-
-            @Override
-            public Future<Void> sendText(String text) throws IOException {
-                CompletableFuture<Void> f = new CompletableFuture<>();
-                session().getRemote().sendString(text, new WriteCallbackImpl(f));
-                return f;
-            }
-
-            @Override
-            public Future<Void> sendPing(ByteBuffer applicationData) throws IOException {
-                CompletableFuture<Void> f = new CompletableFuture<>();
-                session().getRemote().sendPing(applicationData, new WriteCallbackImpl(f));
-                return f;
-            }
-
-            @Override
-            public void close() throws IOException {
-                session().close();
-            }
-
-            private Session session() {
-                Session session = (Session) listener.getProviderSession();
-                if (session == null) {
-                    throw new IllegalStateException("missing session");
-                }
-                return session;
-            }
-        };
-    }
-
-    private static final class WriteCallbackImpl implements WriteCallback {
-        private final CompletableFuture<Void> f;
-
-        WriteCallbackImpl(CompletableFuture<Void> f) {
-            this.f = f;
-        }
-
-        @Override
-        public void writeSuccess() {
-            f.complete(null);
-        }
-
-        @Override
-        public void writeFailed(Throwable x) {
-            f.completeExceptionally(x);
-        }
-    }
-
-    private static Object createWebSocket(JettyServerUpgradeRequest req, JettyServerUpgradeResponse resp) {
-        Listener listener = (Listener) req.getHttpServletRequest().getAttribute(ATTR_LISTENER);
-        if (listener == null) {
-            throw new IllegalStateException("missing listener attribute");
-        }
-        return new WebSocketListener() {
-            @Override
-            public void onWebSocketBinary(byte[] payload, int offset, int length) {
-                listener.onWebSocketBinary(payload, offset, length);
-            }
-
-            @Override
-            public void onWebSocketText(String message) {
-                listener.onWebSocketText(message);
-            }
-
-            @Override
-            public void onWebSocketClose(int statusCode, String reason) {
-                listener.onWebSocketClose(statusCode, reason);
-            }
-
-            @Override
-            public void onWebSocketConnect(Session session) {
-                listener.onWebSocketConnect(session);
-            }
-
-            @Override
-            public void onWebSocketError(Throwable cause) {
-                listener.onWebSocketError(cause);
-            }
-        };
-    }
-
-}
diff --git a/websocket/jetty12-ee8/pom.xml b/websocket/jetty12-ee9/pom.xml
similarity index 95%
rename from websocket/jetty12-ee8/pom.xml
rename to websocket/jetty12-ee9/pom.xml
index 9a7a9ca94545..2253163b3c4c 100644
--- a/websocket/jetty12-ee8/pom.xml
+++ b/websocket/jetty12-ee9/pom.xml
@@ -32,9 +32,9 @@ THE SOFTWARE.
     <relativePath>../..</relativePath>
   </parent>
 
-  <artifactId>websocket-jetty12-ee8</artifactId>
-  <name>Jetty 12 (EE 8) implementation for WebSocket</name>
-  <description>An implementation of the WebSocket handler that works with Jetty 12 (EE 8).</description>
+  <artifactId>websocket-jetty12-ee9</artifactId>
+  <name>Jetty 12 (EE 9) implementation for WebSocket</name>
+  <description>An implementation of the WebSocket handler that works with Jetty 12 (EE 9).</description>
 
   <dependencyManagement>
     <dependencies>
diff --git a/websocket/jetty12-ee8/src/main/java/jenkins/websocket/Jetty12EE8Provider.java b/websocket/jetty12-ee9/src/main/java/jenkins/websocket/Jetty12EE9Provider.java
similarity index 90%
rename from websocket/jetty12-ee8/src/main/java/jenkins/websocket/Jetty12EE8Provider.java
rename to websocket/jetty12-ee9/src/main/java/jenkins/websocket/Jetty12EE9Provider.java
index cc006b180f26..bf6ff9671056 100644
--- a/websocket/jetty12-ee8/src/main/java/jenkins/websocket/Jetty12EE8Provider.java
+++ b/websocket/jetty12-ee9/src/main/java/jenkins/websocket/Jetty12EE9Provider.java
@@ -24,26 +24,26 @@
 
 package jenkins.websocket;
 
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.time.Duration;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Future;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.ee8.websocket.api.Session;
-import org.eclipse.jetty.ee8.websocket.api.WebSocketListener;
-import org.eclipse.jetty.ee8.websocket.api.WriteCallback;
-import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeRequest;
-import org.eclipse.jetty.ee8.websocket.server.JettyServerUpgradeResponse;
-import org.eclipse.jetty.ee8.websocket.server.JettyWebSocketServerContainer;
+import org.eclipse.jetty.ee9.websocket.api.Session;
+import org.eclipse.jetty.ee9.websocket.api.WebSocketListener;
+import org.eclipse.jetty.ee9.websocket.api.WriteCallback;
+import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeRequest;
+import org.eclipse.jetty.ee9.websocket.server.JettyServerUpgradeResponse;
+import org.eclipse.jetty.ee9.websocket.server.JettyWebSocketServerContainer;
 import org.kohsuke.MetaInfServices;
 import org.kohsuke.accmod.Restricted;
 import org.kohsuke.accmod.restrictions.NoExternalUse;
 
 @Restricted(NoExternalUse.class)
 @MetaInfServices(Provider.class)
-public class Jetty12EE8Provider implements Provider {
+public class Jetty12EE9Provider implements Provider {
 
     /**
      * Number of seconds a WebsocketConnection may stay idle until it expires.
@@ -55,11 +55,11 @@ public class Jetty12EE8Provider implements Provider {
      */
     private static long IDLE_TIMEOUT_SECONDS = Long.getLong("jenkins.websocket.idleTimeout", 60L);
 
-    private static final String ATTR_LISTENER = Jetty12EE8Provider.class.getName() + ".listener";
+    private static final String ATTR_LISTENER = Jetty12EE9Provider.class.getName() + ".listener";
 
     private boolean initialized = false;
 
-    public Jetty12EE8Provider() {
+    public Jetty12EE9Provider() {
         JettyWebSocketServerContainer.class.hashCode();
     }
 
@@ -79,7 +79,7 @@ public Handler handle(HttpServletRequest req, HttpServletResponse rsp, Listener
             rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "only WS connections accepted here");
             return null;
         }
-        if (!JettyWebSocketServerContainer.getContainer(req.getServletContext()).upgrade(Jetty12EE8Provider::createWebSocket, req, rsp)) {
+        if (!JettyWebSocketServerContainer.getContainer(req.getServletContext()).upgrade(Jetty12EE9Provider::createWebSocket, req, rsp)) {
             rsp.sendError(HttpServletResponse.SC_BAD_REQUEST, "did not manage to upgrade");
             return null;
         }
diff --git a/websocket/spi/pom.xml b/websocket/spi/pom.xml
index a99aada6a446..178413f92c8e 100644
--- a/websocket/spi/pom.xml
+++ b/websocket/spi/pom.xml
@@ -52,7 +52,7 @@ THE SOFTWARE.
     <dependency>
       <groupId>jakarta.servlet</groupId>
       <artifactId>jakarta.servlet-api</artifactId>
-      <version>4.0.4</version>
+      <version>5.0.0</version>
     </dependency>
   </dependencies>
 
diff --git a/websocket/spi/src/main/java/jenkins/websocket/Provider.java b/websocket/spi/src/main/java/jenkins/websocket/Provider.java
index 19f50f1eaf26..fdb8ec408011 100644
--- a/websocket/spi/src/main/java/jenkins/websocket/Provider.java
+++ b/websocket/spi/src/main/java/jenkins/websocket/Provider.java
@@ -24,11 +24,11 @@
 
 package jenkins.websocket;
 
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.concurrent.Future;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
 
 /**
  * Defines a way for Jenkins core to serve WebSocket connections.