Repository: tipsy/javalin
Pull request #1308 (2021-07-05 10:54:29)

[structure] Move Jetty stuff into jetty package


Patch:
diff --git a/javalin-without-jetty/pom.xml b/javalin-without-jetty/pom.xml
index 7fd60e6b..e8072bce 100644
--- a/javalin-without-jetty/pom.xml
+++ b/javalin-without-jetty/pom.xml
@@ -66,15 +66,13 @@
                             <target name="hacky-mchackface">
                                 <!-- Javalin.java -->
                                 <copy file="${javalin.original.path}" tofile="${javalin.hack.path}" />
+                                <replace file="${javalin.hack.path}" token="protected JavalinJettyServlet javalinJettyServlet" value="private JavalinJettyServlet javalinJettyServlet" />
+                                <replace file="${javalin.hack.path}" token="protected JettyServer jettyServer" value="private JettyServer jettyServer" />
+                                <replace file="${javalin.hack.path}" token="public JettyServer jettyServer() {" value="private JettyServer jettyServer() {" />
                                 <replace file="${javalin.hack.path}" token="public Javalin ws(" value="private Javalin ws(" />
                                 <replace file="${javalin.hack.path}" token="public Javalin wsBefore(" value="private Javalin wsBefore(" />
                                 <replace file="${javalin.hack.path}" token="public Javalin wsAfter(" value="private Javalin wsAfter(" />
                                 <replace file="${javalin.hack.path}" token="public &lt;T extends Exception&gt; Javalin wsException(" value="private &lt;T extends Exception&gt; Javalin wsException(" />
-                                <replace file="${javalin.hack.path}" token="public JavalinWsServlet wsServlet()" value="private JavalinWsServlet wsServlet()" />
-                                <replace file="${javalin.hack.path}" token="protected JavalinWsServlet wsServlet" value="private JavalinWsServlet wsServlet" />
-                                <replace file="${javalin.hack.path}" token="public @Nullable JavalinServer server() {" value="private @Nullable JavalinServer server() {" />
-                                <replace file="${javalin.hack.path}" token="protected JavalinServer server" value="private JavalinServer server" />
-                                <replace file="${javalin.hack.path}" token="protected JavalinServer server" value="private JavalinServer server" />
                                 <replace file="${javalin.hack.path}" token="public Javalin(" value="private Javalin(" />
                                 <replace file="${javalin.hack.path}" token="public static Javalin create(" value="private static Javalin create(" />
                                 <replace file="${javalin.hack.path}" token="public Javalin start(" value="private Javalin start(" />
@@ -82,15 +80,14 @@
                                 <replace file="${javalin.hack.path}" token="public int port(" value="private int port(" />
                                 <!-- JavalinConfig.java -->
                                 <copy file="${javalinconfig.original.path}" tofile="${javalinconfig.hack.path}" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig addStaticFiles(" value="private JavalinConfig addStaticFiles(" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig sessionHandler(" value="private JavalinConfig sessionHandler(" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig wsFactoryConfig(" value="private JavalinConfig wsFactoryConfig(" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig wsLogger(" value="private JavalinConfig wsLogger(" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig enableWebjars()" value="private JavalinConfig enableWebjars()" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig enableDevLogging()" value="private JavalinConfig enableDevLogging()" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig server(" value="private JavalinConfig server(" />
-                                <replace file="${javalinconfig.hack.path}" token="public JavalinConfig configureServletContextHandler(" value="private JavalinConfig configureServletContextHandler(" />
-                                <replace file="${javalinconfig.hack.path}" token="public boolean logIfServerNotStarted = true;" value="public boolean logIfServerNotStarted = false;" />
+                                <replace file="${javalinconfig.hack.path}" token="public void addStaticFiles(" value="private void addStaticFiles(" />
+                                <replace file="${javalinconfig.hack.path}" token="public void sessionHandler(" value="private void sessionHandler(" />
+                                <replace file="${javalinconfig.hack.path}" token="public void wsFactoryConfig(" value="private void wsFactoryConfig(" />
+                                <replace file="${javalinconfig.hack.path}" token="public void wsLogger(" value="private void wsLogger(" />
+                                <replace file="${javalinconfig.hack.path}" token="public void enableWebjars()" value="private void enableWebjars()" />
+                                <replace file="${javalinconfig.hack.path}" token="public void enableDevLogging()" value="private void enableDevLogging()" />
+                                <replace file="${javalinconfig.hack.path}" token="public void server(" value="private void server(" />
+                                <replace file="${javalinconfig.hack.path}" token="public void configureServletContextHandler(" value="private void configureServletContextHandler(" />
                                 <!-- Context.kt -->
                                 <!-- This stopped working for some reason -->
 <!--                                <copy file="${context.original.path}" tofile="${context.hack.path}" />-->
diff --git a/javalin/src/main/java/io/javalin/Javalin.java b/javalin/src/main/java/io/javalin/Javalin.java
index 16e62b88..f820e214 100644
--- a/javalin/src/main/java/io/javalin/Javalin.java
+++ b/javalin/src/main/java/io/javalin/Javalin.java
@@ -10,8 +10,6 @@ package io.javalin;
 import io.javalin.apibuilder.ApiBuilder;
 import io.javalin.apibuilder.EndpointGroup;
 import io.javalin.core.JavalinConfig;
-import io.javalin.core.JavalinServer;
-import io.javalin.core.JettyUtil;
 import io.javalin.core.event.EventListener;
 import io.javalin.core.event.EventManager;
 import io.javalin.core.event.HandlerMetaInfo;
@@ -30,7 +28,9 @@ import io.javalin.http.HandlerType;
 import io.javalin.http.JavalinServlet;
 import io.javalin.http.sse.SseClient;
 import io.javalin.http.sse.SseHandler;
-import io.javalin.websocket.JavalinWsServlet;
+import io.javalin.jetty.JavalinJettyServlet;
+import io.javalin.jetty.JettyServer;
+import io.javalin.jetty.JettyUtil;
 import io.javalin.websocket.WsConfig;
 import io.javalin.websocket.WsExceptionHandler;
 import io.javalin.websocket.WsHandlerType;
@@ -50,20 +50,20 @@ public class Javalin {
      */
     public JavalinConfig _conf = new JavalinConfig();
 
-    protected JavalinServer server; // null in standalone-mode
-    protected JavalinWsServlet wsServlet; // null in standalone-mode
-    protected JavalinServlet servlet = new JavalinServlet(_conf);
+    protected JettyServer jettyServer; // null in standalone-mode
+    protected JavalinJettyServlet javalinJettyServlet; // null in standalone-mode
+    protected JavalinServlet javalinServlet = new JavalinServlet(_conf);
 
     protected EventManager eventManager = new EventManager();
 
     protected Javalin() {
-        this.server = new JavalinServer(_conf);
-        this.wsServlet = new JavalinWsServlet(_conf, servlet);
+        this.jettyServer = new JettyServer(_conf);
+        this.javalinJettyServlet = new JavalinJettyServlet(_conf, javalinServlet);
     }
 
-    public Javalin(JavalinServer server, JavalinWsServlet wsServlet) {
-        this.server = server;
-        this.wsServlet = wsServlet;
+    public Javalin(JettyServer jettyServer, JavalinJettyServlet jettyServlet) {
+        this.jettyServer = jettyServer;
+        this.javalinJettyServlet = jettyServlet;
     }
 
     /**
@@ -88,9 +88,7 @@ public class Javalin {
         Javalin app = new Javalin();
         JavalinValidation.addValidationExceptionMapper(app);
         JavalinConfig.applyUserConfig(app, app._conf, config); // mutates app.config and app (adds http-handlers)
-        if (app._conf.logIfServerNotStarted) {
-            Util.logIfServerNotStarted(app.server);
-        }
+        JettyUtil.maybeLogIfServerNotStarted(app.jettyServer);
         return app;
     }
 
@@ -108,22 +106,15 @@ public class Javalin {
     }
 
     // Get JavalinServlet (for use in standalone mode)
-    public JavalinServlet servlet() {
-        return this.servlet;
-    }
-
-    public JavalinWsServlet wsServlet() {
-        return wsServlet;
+    public JavalinServlet javalinServlet() {
+        return this.javalinServlet;
     }
 
-    /**
-     * Get the JavalinServer
-     */
-    // @formatter:off
-    public @Nullable JavalinServer server() {
-        return this.server;
+    // Get the JavalinServer
+    @Nullable
+    public JettyServer jettyServer() {
+        return this.jettyServer;
     }
-    // @formatter:off
 
     /**
      * Synchronously starts the application instance on the specified port
@@ -136,7 +127,7 @@ public class Javalin {
      * @see Javalin#start()
      */
     public Javalin start(String host, int port) {
-        server.setServerHost(host);
+        jettyServer.setServerHost(host);
         return start(port);
     }
 
@@ -150,7 +141,7 @@ public class Javalin {
      * @see Javalin#start()
      */
     public Javalin start(int port) {
-        server.setServerPort(port);
+        jettyServer.setServerPort(port);
         return start();
     }
 
@@ -166,24 +157,24 @@ public class Javalin {
         Util.logJavalinBanner(this._conf.showJavalinBanner);
         JettyUtil.disableJettyLogger();
         long startupTimer = System.currentTimeMillis();
-        if (server.getStarted()) {
+        if (jettyServer.started) {
             String message = "Server already started. If you are trying to call start() on an instance " +
                 "of Javalin that was stopped using stop(), please create a new instance instead.";
             throw new IllegalStateException(message);
         }
-        server.setStarted(true);
+        jettyServer.started = true;
         Util.printHelpfulMessageIfLoggerIsMissing();
         eventManager.fireEvent(JavalinEvent.SERVER_STARTING);
         try {
             JavalinLogger.info("Starting Javalin ...");
-            server.start(wsServlet);
+            jettyServer.start(javalinJettyServlet);
             Util.logJavalinVersion();
             JavalinLogger.info("Javalin started in " + (System.currentTimeMillis() - startupTimer) + "ms \\o/");
             eventManager.fireEvent(JavalinEvent.SERVER_STARTED);
         } catch (Exception e) {
             JavalinLogger.error("Failed to start Javalin");
             eventManager.fireEvent(JavalinEvent.SERVER_START_FAILED);
-            if (Boolean.TRUE.equals(server.server().getAttribute("is-default-server"))) {
+            if (Boolean.TRUE.equals(jettyServer.server().getAttribute("is-default-server"))) {
                 stop();// stop if server is default server; otherwise, the caller is responsible to stop
             }
             if (e.getMessage() != null && e.getMessage().contains("Failed to bind to")) {
@@ -205,7 +196,7 @@ public class Javalin {
         JavalinLogger.info("Stopping Javalin ...");
         eventManager.fireEvent(JavalinEvent.SERVER_STOPPING);
         try {
-            server.server().stop();
+            jettyServer.server().stop();
         } catch (Exception e) {
             JavalinLogger.error("Javalin failed to stop gracefully", e);
         }
@@ -225,7 +216,7 @@ public class Javalin {
      * Mostly useful if you start the instance with port(0) (random port)
      */
     public int port() {
-        return server.getServerPort();
+        return jettyServer.getServerPort();
     }
 
     /**
@@ -276,7 +267,7 @@ public class Javalin {
      * @see <a href="https://javalin.io/documentation#exception-mapping">Exception mapping in docs</a>
      */
     public <T extends Exception> Javalin exception(@NotNull Class<T> exceptionClass, @NotNull ExceptionHandler<? super T> exceptionHandler) {
-        servlet.getExceptionMapper().getHandlers().put(exceptionClass, (ExceptionHandler<Exception>) exceptionHandler);
+        javalinServlet.getExceptionMapper().getHandlers().put(exceptionClass, (ExceptionHandler<Exception>) exceptionHandler);
         return this;
     }
 
@@ -287,7 +278,7 @@ public class Javalin {
      * @see <a href="https://javalin.io/documentation#error-mapping">Error mapping in docs</a>
      */
     public Javalin error(int statusCode, @NotNull Handler handler) {
-        servlet.getErrorMapper().getErrorHandlerMap().put(statusCode, handler);
+        javalinServlet.getErrorMapper().getErrorHandlerMap().put(statusCode, handler);
         return this;
     }
 
@@ -317,8 +308,8 @@ public class Javalin {
             return addHandler(handlerType, basePath + "/*", handler, roles);
         }
         Set<RouteRole> roleSet = new HashSet<>(Arrays.asList(roles));
-        servlet.addHandler(handlerType, path, handler, roleSet);
-        eventManager.fireHandlerAddedEvent(new HandlerMetaInfo(handlerType, Util.prefixContextPath(servlet.getConfig().contextPath, path), handler, roleSet));
+        javalinServlet.addHandler(handlerType, path, handler, roleSet);
+        eventManager.fireHandlerAddedEvent(new HandlerMetaInfo(handlerType, Util.prefixContextPath(javalinServlet.getConfig().contextPath, path), handler, roleSet));
         return this;
     }
 
@@ -545,7 +536,7 @@ public class Javalin {
      * @see <a href="https://javalin.io/documentation#exception-mapping">Exception mapping in docs</a>
      */
     public <T extends Exception> Javalin wsException(@NotNull Class<T> exceptionClass, @NotNull WsExceptionHandler<? super T> exceptionHandler) {
-        wsServlet.getWsExceptionMapper().getHandlers().put(exceptionClass, (WsExceptionHandler<Exception>) exceptionHandler);
+        javalinJettyServlet.getWsExceptionMapper().getHandlers().put(exceptionClass, (WsExceptionHandler<Exception>) exceptionHandler);
         return this;
     }
 
@@ -555,8 +546,8 @@ public class Javalin {
      */
     private Javalin addWsHandler(@NotNull WsHandlerType handlerType, @NotNull String path, @NotNull Consumer<WsConfig> wsConfig, @NotNull RouteRole... roles) {
         Set<RouteRole> roleSet = new HashSet<>(Arrays.asList(roles));
-        wsServlet.addHandler(handlerType, path, wsConfig, roleSet);
-        eventManager.fireWsHandlerAddedEvent(new WsHandlerMetaInfo(handlerType, Util.prefixContextPath(servlet.getConfig().contextPath, path), wsConfig, roleSet));
+        javalinJettyServlet.addHandler(handlerType, path, wsConfig, roleSet);
+        eventManager.fireWsHandlerAddedEvent(new WsHandlerMetaInfo(handlerType, Util.prefixContextPath(javalinServlet.getConfig().contextPath, path), wsConfig, roleSet));
         return this;
     }
 
diff --git a/javalin/src/main/java/io/javalin/core/JavalinConfig.java b/javalin/src/main/java/io/javalin/core/JavalinConfig.java
index 1db56b35..243e6c5f 100644
--- a/javalin/src/main/java/io/javalin/core/JavalinConfig.java
+++ b/javalin/src/main/java/io/javalin/core/JavalinConfig.java
@@ -25,10 +25,11 @@ import io.javalin.core.util.LogUtil;
 import io.javalin.http.Handler;
 import io.javalin.http.RequestLogger;
 import io.javalin.http.SinglePageHandler;
-import io.javalin.http.staticfiles.JettyResourceHandler;
 import io.javalin.http.staticfiles.Location;
 import io.javalin.http.staticfiles.ResourceHandler;
 import io.javalin.http.staticfiles.StaticFileConfig;
+import io.javalin.jetty.JettyResourceHandler;
+import io.javalin.jetty.JettyUtil;
 import io.javalin.plugin.json.JavalinJackson;
 import io.javalin.plugin.json.JsonMapper;
 import io.javalin.websocket.WsConfig;
@@ -53,7 +54,6 @@ public class JavalinConfig {
     public boolean prefer405over404 = false;
     public boolean enforceSsl = false;
     public boolean showJavalinBanner = true;
-    public boolean logIfServerNotStarted = true;
     public boolean ignoreTrailingSlashes = true;
     @NotNull public String defaultContentType = "text/plain";
     @NotNull public String contextPath = "/";
@@ -120,7 +120,6 @@ public class JavalinConfig {
     }
 
     public void addStaticFiles(@NotNull Consumer<StaticFileConfig> userConfig) {
-        JettyUtil.disableJettyLogger();
         if (inner.resourceHandler == null) {
             inner.resourceHandler = new JettyResourceHandler();
         }
diff --git a/javalin/src/main/java/io/javalin/core/LoomUtil.kt b/javalin/src/main/java/io/javalin/core/LoomUtil.kt
new file mode 100644
index 00000000..1dc3135a
--- /dev/null
+++ b/javalin/src/main/java/io/javalin/core/LoomUtil.kt
@@ -0,0 +1,25 @@
+package io.javalin.core
+
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+object LoomUtil {
+
+    @JvmField
+    var useLoomThreadPool = true
+
+    val loomAvailable = System.getProperty("java.version").contains("loom", ignoreCase = true) || try {
+        Thread::class.java.getDeclaredMethod("startVirtualThread", Runnable::class.java)
+        true
+    } catch (e: Exception) {
+        false
+    }
+
+    fun getExecutorService(): ExecutorService {
+        if (!loomAvailable) {
+            throw IllegalStateException("Your Java version (${System.getProperty("java.version")}) doesn't support Loom")
+        }
+        return Executors::class.java.getMethod("newVirtualThreadExecutor").invoke(Executors::class.java) as ExecutorService
+    }
+
+}
diff --git a/javalin/src/main/java/io/javalin/core/util/Util.kt b/javalin/src/main/java/io/javalin/core/util/Util.kt
index 1db8e7d2..ee84be21 100644
--- a/javalin/src/main/java/io/javalin/core/util/Util.kt
+++ b/javalin/src/main/java/io/javalin/core/util/Util.kt
@@ -6,7 +6,6 @@
 
 package io.javalin.core.util
 
-import io.javalin.core.JavalinServer
 import io.javalin.http.Context
 import io.javalin.http.InternalServerErrorResponse
 import java.io.ByteArrayInputStream
@@ -16,7 +15,6 @@ import java.net.URLEncoder
 import java.util.*
 import java.util.zip.Adler32
 import java.util.zip.CheckedInputStream
-import javax.servlet.http.HttpServletResponse
 
 object Util {
 
@@ -181,24 +179,6 @@ object Util {
         return false
     }
 
-    fun writeResponse(response: HttpServletResponse, responseBody: String, status: Int) {
-        response.status = status
-        ByteArrayInputStream(responseBody.toByteArray()).copyTo(response.outputStream)
-        response.outputStream.close()
-    }
-
-    var logIfNotStarted = true
-
-    @JvmStatic
-    fun logIfServerNotStarted(server: JavalinServer) = Thread {
-        Thread.sleep(5000)
-        if (!server.started && logIfNotStarted) {
-            JavalinLogger.info("It looks like you created a Javalin instance, but you never started it.")
-            JavalinLogger.info("Try: Javalin app = Javalin.create().start();")
-            JavalinLogger.info("For more help, visit https://javalin.io/documentation#starting-and-stopping")
-        }
-    }.start()
-
     @JvmStatic
     fun getPort(e: Exception) = e.message!!.takeLastWhile { it != ':' }
 
@@ -213,11 +193,4 @@ object Util {
         return null
     }
 
-    // jetty throws if client aborts during response writing. testing name avoids hard dependency on jetty.
-    fun isClientAbortException(t: Throwable) = t::class.java.name == "org.eclipse.jetty.io.EofException"
-
-    // Jetty may timeout connections to avoid having broken connections that remain open forever
-    // This is rare, but intended (see issues #163 and #1277)
-    fun isJettyTimeoutException(t: Throwable) = t::class.java.name == "java.util.concurrent.TimeoutException"
-
 }
diff --git a/javalin/src/main/java/io/javalin/http/ExceptionMapper.kt b/javalin/src/main/java/io/javalin/http/ExceptionMapper.kt
index a41c7fd5..0d79b6c6 100644
--- a/javalin/src/main/java/io/javalin/http/ExceptionMapper.kt
+++ b/javalin/src/main/java/io/javalin/http/ExceptionMapper.kt
@@ -8,6 +8,7 @@ package io.javalin.http
 
 import io.javalin.core.util.JavalinLogger
 import io.javalin.core.util.Util
+import io.javalin.jetty.JettyUtil
 import java.util.concurrent.CompletionException
 import javax.servlet.http.HttpServletResponse
 
@@ -47,8 +48,8 @@ class ExceptionMapper {
     }
 
     internal fun handleUnexpectedThrowable(res: HttpServletResponse, throwable: Throwable): Nothing? {
-        if (Util.isClientAbortException(throwable)) return null // aborts can be ignored
-        if (Util.isJettyTimeoutException(throwable)) return null // jetty timeouts can be ignored
+        if (JettyUtil.isClientAbortException(throwable)) return null // jetty aborts aren't actually unexpected
+        if (JettyUtil.isJettyTimeoutException(throwable)) return null // jetty timeouts aren't actually unexpected
         res.status = 500
         JavalinLogger.error("Exception occurred while servicing http-request", throwable)
         return null
diff --git a/javalin/src/main/java/io/javalin/http/HttpCode.kt b/javalin/src/main/java/io/javalin/http/HttpCode.kt
index f944deba..f50ebfdc 100644
--- a/javalin/src/main/java/io/javalin/http/HttpCode.kt
+++ b/javalin/src/main/java/io/javalin/http/HttpCode.kt
@@ -4,7 +4,6 @@ enum class HttpCode(
         val status: Int,
         val message: String
 ) {
-
     CONTINUE(100, "Continue"),
     SWITCHING_PROTOCOLS(101, "Switching Protocols"),
     PROCESSING(102, "Processing"),
diff --git a/javalin/src/main/java/io/javalin/http/JavalinServlet.kt b/javalin/src/main/java/io/javalin/http/JavalinServlet.kt
index 47b32cde..3e529049 100644
--- a/javalin/src/main/java/io/javalin/http/JavalinServlet.kt
+++ b/javalin/src/main/java/io/javalin/http/JavalinServlet.kt
@@ -46,7 +46,7 @@ class JavalinServlet(val config: JavalinConfig) : HttpServlet() {
                 if (type == HandlerType.HEAD && hasGetHandlerMapped(requestUri)) {
                     return@tryWithExceptionMapper // return 200, there is a get handler
                 }
-                if (type == HandlerType.HEAD || type == HandlerType.GET) { // let Jetty check for static resources (will write response if found)
+                if (type == HandlerType.HEAD || type == HandlerType.GET) { // check for static resources (will write response if found)
                     if (config.inner.resourceHandler?.handle(req, JavalinResponseWrapper(res, rwc)) == true) return@tryWithExceptionMapper
                     if (config.inner.singlePageHandler.handle(ctx)) return@tryWithExceptionMapper
                 }
diff --git a/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt b/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
index 37aa1df7..5ef4ec73 100644
--- a/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
+++ b/javalin/src/main/java/io/javalin/http/util/ContextUtil.kt
@@ -12,8 +12,8 @@ import io.javalin.core.util.JavalinLogger
 import io.javalin.http.Context
 import io.javalin.http.HandlerEntry
 import io.javalin.http.HandlerType
+import io.javalin.http.HttpCode
 import io.javalin.http.HttpResponseException
-import org.eclipse.jetty.http.HttpStatus
 import java.net.URL
 import java.net.URLDecoder
 import java.util.*
@@ -96,7 +96,7 @@ object ContextUtil {
         val maxRequestSize = this.appAttribute<Long>(maxRequestSizeKey)
         if (this.req.contentLength > maxRequestSize) {
             JavalinLogger.warn("Body greater than max size ($maxRequestSize bytes)")
-            throw HttpResponseException(HttpStatus.PAYLOAD_TOO_LARGE_413, "Payload too large")
+            throw HttpResponseException(HttpCode.PAYLOAD_TOO_LARGE.status, HttpCode.PAYLOAD_TOO_LARGE.message)
         }
     }
 
diff --git a/javalin/src/main/java/io/javalin/http/util/RedirectToLowercasePathPlugin.kt b/javalin/src/main/java/io/javalin/http/util/RedirectToLowercasePathPlugin.kt
index 0290aa9a..6d1d90f4 100644
--- a/javalin/src/main/java/io/javalin/http/util/RedirectToLowercasePathPlugin.kt
+++ b/javalin/src/main/java/io/javalin/http/util/RedirectToLowercasePathPlugin.kt
@@ -36,7 +36,7 @@ class RedirectToLowercasePathPlugin : Plugin, PluginLifecycleInit {
         app.before { ctx ->
             val type = HandlerType.fromServletRequest(ctx.req)
             val requestUri = ctx.req.requestURI.removePrefix(ctx.req.contextPath)
-            val matcher = app.servlet().matcher
+            val matcher = app.javalinServlet().matcher
             matcher.findEntries(type, requestUri).firstOrNull()?.let {
                 return@before // we found a route for this case, no need to redirect
             }
diff --git a/javalin/src/main/java/io/javalin/websocket/JavalinWsServlet.kt b/javalin/src/main/java/io/javalin/jetty/JavalinJettyServlet.kt
similarity index 86%
rename from javalin/src/main/java/io/javalin/websocket/JavalinWsServlet.kt
rename to javalin/src/main/java/io/javalin/jetty/JavalinJettyServlet.kt
index 1f9ee11b..954910f5 100644
--- a/javalin/src/main/java/io/javalin/websocket/JavalinWsServlet.kt
+++ b/javalin/src/main/java/io/javalin/jetty/JavalinJettyServlet.kt
@@ -4,7 +4,7 @@
  * Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
  */
 
-package io.javalin.websocket
+package io.javalin.jetty
 
 import io.javalin.core.JavalinConfig
 import io.javalin.core.security.RouteRole
@@ -13,6 +13,12 @@ import io.javalin.http.Context
 import io.javalin.http.JavalinServlet
 import io.javalin.http.UnauthorizedResponse
 import io.javalin.http.util.ContextUtil
+import io.javalin.websocket.WsConfig
+import io.javalin.websocket.WsConnection
+import io.javalin.websocket.WsEntry
+import io.javalin.websocket.WsExceptionMapper
+import io.javalin.websocket.WsHandlerType
+import io.javalin.websocket.WsPathMatcher
 import org.eclipse.jetty.websocket.api.WebSocketConstants
 import org.eclipse.jetty.websocket.servlet.WebSocketCreator
 import org.eclipse.jetty.websocket.servlet.WebSocketServlet
@@ -26,26 +32,16 @@ internal const val upgradeContextKey = "javalin-ws-upgrade-context"
 internal const val upgradeSessionAttrsKey = "javalin-ws-upgrade-http-session"
 
 /**
- * The JavalinWsServlet is responsible for both WebSocket and HTTP requests.
- * It extends Jetty's WebSocketServlet, and has a HTTP Servlet as a constructor arg.
+ * The [JavalinJettyServlet] is responsible for both WebSocket and HTTP requests.
+ * It extends Jetty's [WebSocketServlet], and has a [JavalinServlet] as a constructor arg.
  * It switches between WebSocket and HTTP in the [service] method.
  */
-class JavalinWsServlet(val config: JavalinConfig, private val httpServlet: JavalinServlet) : WebSocketServlet() {
+class JavalinJettyServlet(val config: JavalinConfig, private val httpServlet: JavalinServlet) : WebSocketServlet() {
 
     val wsExceptionMapper = WsExceptionMapper()
 
     private val wsPathMatcher = WsPathMatcher()
 
-    override fun configure(factory: WebSocketServletFactory) {
-        config.inner.wsFactoryConfig?.accept(factory)
-        factory.creator = WebSocketCreator { req, res ->
-            val preUpgradeContext = req.httpServletRequest.getAttribute(upgradeContextKey) as Context
-            req.httpServletRequest.setAttribute(upgradeContextKey, ContextUtil.changeBaseRequest(preUpgradeContext, req.httpServletRequest))
-            req.httpServletRequest.setAttribute(upgradeSessionAttrsKey, req.session?.attributeNames?.asSequence()?.associateWith { req.session.getAttribute(it) })
-            return@WebSocketCreator WsConnection(wsPathMatcher, wsExceptionMapper, config.inner.wsLogger)
-        }
-    }
-
     override fun service(req: HttpServletRequest, res: HttpServletResponse) { // this handles both http and websocket
         if (!req.isWebSocket()) {
             return httpServlet.service(req, res)
@@ -73,6 +69,17 @@ class JavalinWsServlet(val config: JavalinConfig, private val httpServlet: Javal
         }
     }
 
+    // called after service
+    override fun configure(factory: WebSocketServletFactory) {
+        config.inner.wsFactoryConfig?.accept(factory)
+        factory.creator = WebSocketCreator { req, res ->
+            val preUpgradeContext = req.httpServletRequest.getAttribute(upgradeContextKey) as Context
+            req.httpServletRequest.setAttribute(upgradeContextKey, ContextUtil.changeBaseRequest(preUpgradeContext, req.httpServletRequest))
+            req.httpServletRequest.setAttribute(upgradeSessionAttrsKey, req.session?.attributeNames?.asSequence()?.associateWith { req.session.getAttribute(it) })
+            return@WebSocketCreator WsConnection(wsPathMatcher, wsExceptionMapper, config.inner.wsLogger)
+        }
+    }
+
     fun addHandler(handlerType: WsHandlerType, path: String, ws: Consumer<WsConfig>, roles: Set<RouteRole>) {
         wsPathMatcher.add(WsEntry(handlerType, path, config.ignoreTrailingSlashes, WsConfig().apply { ws.accept(this) }, roles))
     }
diff --git a/javalin/src/main/java/io/javalin/http/staticfiles/PrecompressingResourceHandler.kt b/javalin/src/main/java/io/javalin/jetty/JettyPrecompressingResourceHandler.kt
similarity index 98%
rename from javalin/src/main/java/io/javalin/http/staticfiles/PrecompressingResourceHandler.kt
rename to javalin/src/main/java/io/javalin/jetty/JettyPrecompressingResourceHandler.kt
index e7beceb0..2db4d83c 100644
--- a/javalin/src/main/java/io/javalin/http/staticfiles/PrecompressingResourceHandler.kt
+++ b/javalin/src/main/java/io/javalin/jetty/JettyPrecompressingResourceHandler.kt
@@ -1,4 +1,4 @@
-package io.javalin.http.staticfiles
+package io.javalin.jetty
 
 import io.javalin.core.util.Header
 import io.javalin.core.util.JavalinLogger
@@ -15,7 +15,7 @@ import javax.servlet.http.HttpServletRequest
 import javax.servlet.http.HttpServletResponse
 
 
-object PrecompressingResourceHandler {
+object JettyPrecompressingResourceHandler {
 
     val compressedFiles = ConcurrentHashMap<String, ByteArray>()
     var resourceMaxSize: Int = 2 * 1024 * 1024 // the unit of resourceMaxSize is byte
diff --git a/javalin/src/main/java/io/javalin/http/staticfiles/JettyResourceHandler.kt b/javalin/src/main/java/io/javalin/jetty/JettyResourceHandler.kt
similarity index 87%
rename from javalin/src/main/java/io/javalin/http/staticfiles/JettyResourceHandler.kt
rename to javalin/src/main/java/io/javalin/jetty/JettyResourceHandler.kt
index 6c7e7a1f..55eacd50 100644
--- a/javalin/src/main/java/io/javalin/http/staticfiles/JettyResourceHandler.kt
+++ b/javalin/src/main/java/io/javalin/jetty/JettyResourceHandler.kt
@@ -4,11 +4,12 @@
  * Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
  */
 
-package io.javalin.http.staticfiles
+package io.javalin.jetty
 
 import io.javalin.core.util.JavalinLogger
-import io.javalin.core.util.Util
 import io.javalin.http.JavalinResponseWrapper
+import io.javalin.http.staticfiles.Location
+import io.javalin.http.staticfiles.StaticFileConfig
 import org.eclipse.jetty.server.Request
 import org.eclipse.jetty.server.handler.ResourceHandler
 import org.eclipse.jetty.util.URIUtil
@@ -22,6 +23,10 @@ import io.javalin.http.staticfiles.ResourceHandler as JavalinResourceHandler
 
 class JettyResourceHandler : JavalinResourceHandler {
 
+    init {
+        JettyUtil.disableJettyLogger()
+    }
+
     val handlers = mutableListOf<ConfigurableHandler>()
 
     override fun addStaticFileConfig(config: StaticFileConfig) {
@@ -36,7 +41,7 @@ class JettyResourceHandler : JavalinResourceHandler {
                 val resource = handler.getResource(target)
                 if (resource.isFile() || resource.isDirectoryWithWelcomeFile(handler, target)) {
                     handler.config.headers.forEach { httpResponse.setHeader(it.key, it.value) }
-                    if (handler.config.precompress && PrecompressingResourceHandler.handle(resource, httpRequest, httpResponse)) {
+                    if (handler.config.precompress && JettyPrecompressingResourceHandler.handle(resource, httpRequest, httpResponse)) {
                         return true
                     }
                     httpResponse.contentType = null // Jetty will only set the content-type if it's null
@@ -46,7 +51,7 @@ class JettyResourceHandler : JavalinResourceHandler {
                     return true
                 }
             } catch (e: Exception) { // it's fine, we'll just 404
-                if (!Util.isClientAbortException(e)) {
+                if (!JettyUtil.isClientAbortException(e)) {
                     JavalinLogger.info("Exception occurred while handling static resource", e)
                 }
             }
@@ -57,7 +62,7 @@ class JettyResourceHandler : JavalinResourceHandler {
     private fun Resource?.isFile() = this != null && this.exists() && !this.isDirectory
 
     private fun Resource?.isDirectoryWithWelcomeFile(handler: ResourceHandler, target: String) =
-            this != null && this.isDirectory && handler.getResource("${target.removeSuffix("/")}/index.html")?.exists() == true
+        this != null && this.isDirectory && handler.getResource("${target.removeSuffix("/")}/index.html")?.exists() == true
 }
 
 open class ConfigurableHandler(val config: StaticFileConfig) : ResourceHandler() {
@@ -66,10 +71,12 @@ open class ConfigurableHandler(val config: StaticFileConfig) : ResourceHandler()
         resourceBase = getResourceBase(config)
         isDirAllowed = false
         isEtags = true
-        JavalinLogger.info("""Static file handler added:
+        JavalinLogger.info(
+            """Static file handler added:
         |    {hostedPath: "${config.hostedPath}", directory: "${config.directory}", location: Location.${config.location}}
         |    Resolved path: '${getResourceBase(config)}'
-        """.trimMargin())
+        """.trimMargin()
+        )
     }
 
     override fun getResource(path: String): Resource {
diff --git a/javalin/src/main/java/io/javalin/core/JavalinServer.kt b/javalin/src/main/java/io/javalin/jetty/JettyServer.kt
similarity index 96%
rename from javalin/src/main/java/io/javalin/core/JavalinServer.kt
rename to javalin/src/main/java/io/javalin/jetty/JettyServer.kt
index de1ef7d8..716d420b 100644
--- a/javalin/src/main/java/io/javalin/core/JavalinServer.kt
+++ b/javalin/src/main/java/io/javalin/jetty/JettyServer.kt
@@ -4,11 +4,11 @@
  * Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
  */
 
-package io.javalin.core
+package io.javalin.jetty
 
+import io.javalin.core.JavalinConfig
 import io.javalin.core.util.JavalinLogger
 import io.javalin.core.util.Util
-import io.javalin.websocket.JavalinWsServlet
 import org.eclipse.jetty.server.Handler
 import org.eclipse.jetty.server.HttpConnectionFactory
 import org.eclipse.jetty.server.Request
@@ -23,8 +23,9 @@ import java.net.BindException
 import javax.servlet.http.HttpServletRequest
 import javax.servlet.http.HttpServletResponse
 
-class JavalinServer(val config: JavalinConfig) {
+class JettyServer(val config: JavalinConfig) {
 
+    @JvmField
     var started = false
     var serverPort = -1
     var serverHost: String? = null
@@ -35,7 +36,7 @@ class JavalinServer(val config: JavalinConfig) {
     }
 
     @Throws(BindException::class)
-    fun start(wsAndHttpServlet: JavalinWsServlet) {
+    fun start(wsAndHttpServlet: JavalinJettyServlet) {
         if (serverPort == -1 && config.inner.server == null) {
             serverPort = 8080
             JavalinLogger.info("No port specified, starting on port $serverPort. Call start(port) to change ports.")
diff --git a/javalin/src/main/java/io/javalin/core/JettyUtil.kt b/javalin/src/main/java/io/javalin/jetty/JettyUtil.kt
similarity index 69%
rename from javalin/src/main/java/io/javalin/core/JettyUtil.kt
rename to javalin/src/main/java/io/javalin/jetty/JettyUtil.kt
index 09cf2a91..8962ddb7 100644
--- a/javalin/src/main/java/io/javalin/core/JettyUtil.kt
+++ b/javalin/src/main/java/io/javalin/jetty/JettyUtil.kt
@@ -1,5 +1,6 @@
-package io.javalin.core
+package io.javalin.jetty
 
+import io.javalin.core.LoomUtil
 import io.javalin.core.LoomUtil.loomAvailable
 import io.javalin.core.LoomUtil.useLoomThreadPool
 import io.javalin.core.util.JavalinLogger
@@ -8,12 +9,10 @@ import org.eclipse.jetty.server.Server
 import org.eclipse.jetty.server.handler.StatisticsHandler
 import org.eclipse.jetty.util.thread.QueuedThreadPool
 import org.eclipse.jetty.util.thread.ThreadPool
-import java.util.concurrent.ExecutorService
-import java.util.concurrent.Executors
 
-object JettyUtil {
+private var defaultLogger: org.eclipse.jetty.util.log.Logger? = null
 
-    private var defaultLogger: org.eclipse.jetty.util.log.Logger? = null
+object JettyUtil {
 
     @JvmStatic
     fun getOrDefault(server: Server?) = server ?: Server(defaultThreadPool()).apply {
@@ -44,6 +43,24 @@ object JettyUtil {
         org.eclipse.jetty.util.log.Log.setLog(defaultLogger)
     }
 
+    var logIfNotStarted = true
+
+    @JvmStatic
+    fun maybeLogIfServerNotStarted(jettyServer: JettyServer) = Thread {
+        Thread.sleep(5000)
+        if (logIfNotStarted && !jettyServer.started) {
+            JavalinLogger.info("It looks like you created a Javalin instance, but you never started it.")
+            JavalinLogger.info("Try: Javalin app = Javalin.create().start();")
+            JavalinLogger.info("For more help, visit https://javalin.io/documentation#starting-and-stopping")
+        }
+    }.start()
+
+    // jetty throws if client aborts during response writing. testing name avoids hard dependency on jetty.
+    fun isClientAbortException(t: Throwable) = t::class.java.name == "org.eclipse.jetty.io.EofException"
+
+    // Jetty may timeout connections to avoid having broken connections that remain open forever
+    // This is rare, but intended (see issues #163 and #1277)
+    fun isJettyTimeoutException(t: Throwable) = t::class.java.name == "java.util.concurrent.TimeoutException"
 
     class NoopLogger : org.eclipse.jetty.util.log.Logger {
         override fun getName() = "noop"
@@ -65,25 +82,6 @@ object JettyUtil {
 
 }
 
-object LoomUtil {
-
-    @JvmField
-    var useLoomThreadPool = true
-    val loomAvailable = System.getProperty("java.version").contains("loom", ignoreCase = true) || try {
-        Thread::class.java.getDeclaredMethod("startVirtualThread", Runnable::class.java)
-        true
-    } catch (e: Exception) {
-        false
-    }
-
-    fun getExecutorService(): ExecutorService {
-        if (!loomAvailable) {
-            throw IllegalStateException("Your Java version (${System.getProperty("java.version")}) doesn't support Loom")
-        }
-        return Executors::class.java.getMethod("newVirtualThreadExecutor").invoke(Executors::class.java) as ExecutorService
-    }
-}
-
 class LoomThreadPool : ThreadPool {
 
     private val executorService = LoomUtil.getExecutorService()
@@ -97,3 +95,4 @@ class LoomThreadPool : ThreadPool {
     override fun getIdleThreads() = 1
     override fun isLowOnThreads() = false
 }
+
diff --git a/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt b/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
index 29cd31f0..5e7b79ae 100644
--- a/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
+++ b/javalin/src/main/java/io/javalin/plugin/json/JavalinJackson.kt
@@ -12,22 +12,20 @@ import io.javalin.core.util.OptionalDependency
 import io.javalin.core.util.Util
 import java.io.InputStream
 
-val defaultMapper: ObjectMapper by lazy {
-    try {
-        val className = OptionalDependency.JACKSON_KT.testClass
-        ObjectMapper().registerModule(Class.forName(className).getConstructor().newInstance() as Module)
-    } catch (e: ClassNotFoundException) {
-        ObjectMapper()
-    }
+private fun defaultMapper(): ObjectMapper = try {
+    val className = OptionalDependency.JACKSON_KT.testClass
+    ObjectMapper().registerModule(Class.forName(className).getConstructor().newInstance() as Module)
+} catch (e: ClassNotFoundException) {
+    ObjectMapper()
 }
 
-class JavalinJackson(val objectMapper: ObjectMapper = defaultMapper) : JsonMapper {
+class JavalinJackson(private var objectMapper: ObjectMapper? = null) : JsonMapper {
 
     override fun toJsonString(obj: Any): String {
         ensureDependenciesPresent()
         return when (obj) {
             is String -> obj // the default mapper treats strings as if they are already JSON
-            else -> objectMapper.writeValueAsString(obj) // convert object to JSON
+            else -> objectMapper!!.writeValueAsString(obj) // convert object to JSON
         }
     }
 
@@ -36,19 +34,19 @@ class JavalinJackson(val objectMapper: ObjectMapper = defaultMapper) : JsonMappe
         return when (obj) {
             is String -> obj.byteInputStream() // the default mapper treats strings as if they are already JSON
             else -> PipedStreamUtil.getInputStream { pipedOutputStream ->
-                objectMapper.factory.createGenerator(pipedOutputStream).writeObject(obj)
+                objectMapper!!.factory.createGenerator(pipedOutputStream).writeObject(obj)
             }
         }
     }
 
     override fun <T> fromJsonString(json: String, targetClass: Class<T>): T {
         ensureDependenciesPresent(targetClass)
-        return objectMapper.readValue(json, targetClass)
+        return objectMapper!!.readValue(json, targetClass)
     }
 
     override fun <T : Any?> fromJsonStream(json: InputStream, targetClass: Class<T>): T {
         ensureDependenciesPresent(targetClass)
-        return objectMapper.readValue(json, targetClass)
+        return objectMapper!!.readValue(json, targetClass)
     }
 
     private fun ensureDependenciesPresent(targetClass: Class<*>? = null) {
@@ -56,6 +54,7 @@ class JavalinJackson(val objectMapper: ObjectMapper = defaultMapper) : JsonMappe
         if (targetClass != null && Util.isKotlinClass(targetClass)) {
             Util.ensureDependencyPresent(OptionalDependency.JACKSON_KT)
         }
+        objectMapper = objectMapper ?: defaultMapper()
     }
 
 }
diff --git a/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt b/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt
index b32daf0e..ac418dc6 100644
--- a/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt
+++ b/javalin/src/main/java/io/javalin/plugin/metrics/MicrometerPlugin.kt
@@ -35,7 +35,7 @@ class MicrometerPlugin @JvmOverloads constructor(
 ) : Plugin {
     override fun apply(app: Javalin) {
         Util.ensureDependencyPresent(OptionalDependency.MICROMETER)
-        app.server()?.server()?.let { server ->
+        app.jettyServer()?.server()?.let { server ->
             if (tagExceptionName) {
                 app.exception(Exception::class.java, EXCEPTION_HANDLER)
             }
@@ -50,7 +50,7 @@ class MicrometerPlugin @JvmOverloads constructor(
                     val pathInfo = request.pathInfo.removePrefix(app._conf.contextPath).prefixIfNot("/")
                     response.setHeader(EXCEPTION_HEADER, null)
                     val handlerType = HandlerType.valueOf(request.method)
-                    val uri = app.servlet().matcher.findEntries(handlerType, pathInfo).asSequence()
+                    val uri = app.javalinServlet().matcher.findEntries(handlerType, pathInfo).asSequence()
                         .map { it.path }
                         .map { if (it == "/" || it.isBlank()) "root" else it }
                         .map { if (!tagRedirectPaths && response.status in 300..399) "REDIRECTION" else it }
diff --git a/javalin/src/main/java/io/javalin/websocket/WsContext.kt b/javalin/src/main/java/io/javalin/websocket/WsContext.kt
index cdc913b8..babeaf29 100644
--- a/javalin/src/main/java/io/javalin/websocket/WsContext.kt
+++ b/javalin/src/main/java/io/javalin/websocket/WsContext.kt
@@ -7,6 +7,8 @@
 package io.javalin.websocket
 
 import io.javalin.http.Context
+import io.javalin.jetty.upgradeContextKey
+import io.javalin.jetty.upgradeSessionAttrsKey
 import io.javalin.plugin.json.jsonMapper
 import org.eclipse.jetty.websocket.api.RemoteEndpoint
 import org.eclipse.jetty.websocket.api.Session


Test patch:
diff --git a/javalin/src/test/java/io/javalin/TestConfiguration.kt b/javalin/src/test/java/io/javalin/TestConfiguration.kt
index 5af571a4..926b8723 100644
--- a/javalin/src/test/java/io/javalin/TestConfiguration.kt
+++ b/javalin/src/test/java/io/javalin/TestConfiguration.kt
@@ -39,7 +39,6 @@ class TestConfiguration {
             it.registerPlugin(RouteOverviewPlugin("/test"))
             it.enableWebjars()
             it.enforceSsl = true
-            it.logIfServerNotStarted = false
             it.prefer405over404 = false
             it.requestLogger { ctx, executionTimeMs -> }
             it.sessionHandler { SessionHandler() }
@@ -64,7 +63,7 @@ class TestConfiguration {
                 })
             }
         }.start(0)
-        assertThat(app.server.started).isTrue()
+        assertThat(app.jettyServer.started).isTrue()
         app.stop()
     }
 
diff --git a/javalin/src/test/java/io/javalin/TestMaxRequestSize.kt b/javalin/src/test/java/io/javalin/TestMaxRequestSize.kt
index 80641ab1..b018d54b 100644
--- a/javalin/src/test/java/io/javalin/TestMaxRequestSize.kt
+++ b/javalin/src/test/java/io/javalin/TestMaxRequestSize.kt
@@ -29,7 +29,7 @@ class TestMaxRequestSize {
     @Test
     fun `can read payloads larger than max size by using inputstream`() = TestUtil.test(Javalin.create { it.maxRequestSize = 4L }) { app, http ->
         app.post("/body") { ctx -> ctx.result(ctx.body()) }
-        assertThat(http.post("/body").body("123456").asString().body).isEqualTo("Payload too large")
+        assertThat(http.post("/body").body("123456").asString().body).isEqualTo("Payload Too Large")
         app.post("/stream") { ctx -> ctx.result(ctx.req.inputStream.readBytes()) }
         assertThat(http.post("/stream").body("123456").asString().body).isEqualTo("123456")
     }
diff --git a/javalin/src/test/java/io/javalin/staticfiles/TestStaticFilesPrecompressor.kt b/javalin/src/test/java/io/javalin/staticfiles/TestStaticFilesPrecompressor.kt
index 8c1567c0..9d96c60f 100644
--- a/javalin/src/test/java/io/javalin/staticfiles/TestStaticFilesPrecompressor.kt
+++ b/javalin/src/test/java/io/javalin/staticfiles/TestStaticFilesPrecompressor.kt
@@ -11,7 +11,7 @@ import io.javalin.core.compression.Brotli
 import io.javalin.core.compression.Gzip
 import io.javalin.core.util.Header
 import io.javalin.core.util.OptionalDependency
-import io.javalin.http.staticfiles.PrecompressingResourceHandler
+import io.javalin.jetty.JettyPrecompressingResourceHandler
 import io.javalin.testing.HttpUtil
 import io.javalin.testing.TestUtil
 import okhttp3.OkHttpClient
@@ -65,11 +65,11 @@ class TestStaticFilesPrecompressor {
 
     @Test
     fun `only creates one compressed version even if query params are present`() = TestUtil.test(configPrecompressionStaticResourceApp) { _, http ->
-        val oldSize = PrecompressingResourceHandler.compressedFiles.size
+        val oldSize = JettyPrecompressingResourceHandler.compressedFiles.size
         assertThat(http.getFile("/secret.html", "gzip").contentEncoding()).isEqualTo("gzip")
         assertThat(http.getFile("/secret.html?qp=1", "gzip").contentEncoding()).isEqualTo("gzip")
         assertThat(http.getFile("/secret.html?qp=2", "gzip").contentEncoding()).isEqualTo("gzip")
-        assertThat(PrecompressingResourceHandler.compressedFiles.size <= oldSize + 1)
+        assertThat(JettyPrecompressingResourceHandler.compressedFiles.size <= oldSize + 1)
     }
 
     private fun Response.contentLength() = this.headers.get(Header.CONTENT_LENGTH)