When using Jetty version 10.0.0 up to 10.0.3 and Java 11 (openjdk 11.0.7 2020-04-14) Spring Boot 2.5.0 can't start.
It can be reproduced from https://start.spring.io/
Modify the pom.xml as per Spring Boot 2.5.documentation
<?xml version="1.0" encoding="UTF-8"?>
<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.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/>
<!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
<jetty.version>10.0.3</jetty.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
It ends up in the following stacktrace :
2021-06-10 08:41:04.659 ERROR 850316 --- [ main] o.s.boot.SpringApplication : Application run failed
2021-06-10 08:53:04.698 ERROR 853100 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Jetty web server
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:163) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:577) ~[spring-context-5.3.7.jar!/:5.3.7]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:758) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:337) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1336) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1325) ~[spring-boot-2.5.0.jar!/:2.5.0]
at com.example.demo.DemoApplication.main(DemoApplication.java:10) ~[classes!/:0.0.1-SNAPSHOT]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:108) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start embedded Jetty web server
at org.springframework.boot.web.embedded.jetty.JettyWebServer.initialize(JettyWebServer.java:129) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.web.embedded.jetty.JettyWebServer.<init>(JettyWebServer.java:90) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory.getJettyWebServer(JettyServletWebServerFactory.java:429) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory.getWebServer(JettyServletWebServerFactory.java:170) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.createWebServer(ServletWebServerApplicationContext.java:182) ~[spring-boot-2.5.0.jar!/:2.5.0]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.onRefresh(ServletWebServerApplicationContext.java:160) ~[spring-boot-2.5.0.jar!/:2.5.0]
... 16 common frames omitted
Caused by: java.lang.NoClassDefFoundError: org/eclipse/jetty/websocket/servlet/WebSocketCreator
at org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer.initialize(NativeWebSocketServletContainerInitializer.java:63) ~[websocket-server-9.4.41.v20210516.jar!/:9.4.41.v20210516]
at org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.initialize(WebSocketServerContainerInitializer.java:196) ~[javax-websocket-server-impl-9.4.41.v20210516.jar!/:9.4.41.v20210516]
at org.springframework.boot.autoconfigure.websocket.servlet.JettyWebSocketServletWebServerCustomizer$1.configure(JettyWebSocketServletWebServerCustomizer.java:46) ~[spring-boot-autoconfigure-2.5.0.jar!/:2.5.0]
at org.eclipse.jetty.webapp.Configurations.configure(Configurations.java:508) ~[jetty-webapp-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.webapp.WebAppContext.configure(WebAppContext.java:514) ~[jetty-webapp-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1300) ~[jetty-webapp-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:879) ~[jetty-server-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:306) ~[jetty-servlet-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:532) ~[jetty-webapp-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:171) ~[jetty-util-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.server.Server.start(Server.java:469) ~[jetty-server-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:114) ~[jetty-util-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:89) ~[jetty-server-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.server.Server.doStart(Server.java:414) ~[jetty-server-10.0.3.jar!/:10.0.3]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:93) ~[jetty-util-10.0.3.jar!/:10.0.3]
at org.springframework.boot.web.embedded.jetty.JettyWebServer.initialize(JettyWebServer.java:123) ~[spring-boot-2.5.0.jar!/:2.5.0]
... 21 common frames omitted
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.websocket.servlet.WebSocketCreator
at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:589) ~[na:na]
at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151) ~[demo-0.0.1-SNAPSHOT.jar:0.0.1-SNAPSHOT]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
... 38 common frames omitted
Comment From: snicoll
Thanks Christophe, I've reproduced the problem.
Comment From: snicoll
Workaround for the time being is to exclude the auto-configuration, e.g.:
@SpringBootApplication(exclude = WebSocketServletAutoConfiguration.class)
Comment From: snicoll
Our starter has a direct dependency on org.eclipse.jetty.websocket:websocket-server
. In Jetty 10, this library does not exist and the replacement seems to be websocket-jetty-server
.
A sample project above means that we still bring websocket-server
on the classpath (v9) and we don't bring Jetty 10's WebSocket support. Patching the pom to bring the necessary jar still breaks with a different type this time:
Caused by: java.lang.ClassNotFoundException: org.eclipse.jetty.websocket.server.NativeWebSocketServletContainerInitializer
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581) ~[na:na]
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178) ~[na:na]
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522) ~[na:na]
... 29 common frames omitted
Comment From: wilkinsona
I've updated the release notes to reflect the current situation. Rather than excluding the WebSocket auto-configuration, I'd recommend excluding the unwanted Jetty 9-specific dependencies instead. This avoids having Jetty modules from two different versions on the classpath.
Comment From: wilkinsona
To get WebSockets going with Jetty 10 two additional dependencies are needed:
org.eclipse.jetty.websocket:websocket-javax-server
org.eclipse.jetty.websocket:websocket-jetty-server
You also need to add a WebServerFactoryCustomizer
to replace the auto-configuration which has backed off due to Jetty 9's org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer
being absent:
class JettyWebSocketServletWebServerCustomizer implements WebServerFactoryCustomizer<JettyServletWebServerFactory>, Ordered {
@Override
public void customize(JettyServletWebServerFactory factory) {
factory.addConfigurations(new AbstractConfiguration() {
@Override
public void configure(WebAppContext context) throws Exception {
Context servletContext = context.getServletContext();
JettyWebSocketServerContainer jettyContainer = JettyWebSocketServerContainer.getContainer(servletContext);
Server server = context.getServer();
if (jettyContainer == null) {
WebSocketServerComponents.ensureWebSocketComponents(server, servletContext);
JettyWebSocketServerContainer.ensureContainer(servletContext);
}
JavaxWebSocketServerContainer javaxContainer = JavaxWebSocketServerContainer.getContainer(servletContext);
if (javaxContainer == null) {
WebSocketServerComponents.ensureWebSocketComponents(server, servletContext);
WebSocketUpgradeFilter.ensureFilter(servletContext);
WebSocketMappings.ensureMappings(servletContext);
JavaxWebSocketServerContainer.ensureContainer(servletContext);
}
}
});
}
@Override
public int getOrder() {
return 0;
}
}
We should be able to include the customiser (modified to use reflection) in the auto-configuration so that only the dependency juggling is necessary.
Comment From: leozhang123
Has this problem been fixed? I also found this problem in the new version. springboot 2.5.5 and jdk 17,jetty 10.0.6
Comment From: snicoll
@leozhang123 I am not sure I understand your question. This issue is closed in a milestone with additional tests, so yes we believe it is fixed. If you think you've found an issue, please create a separate issue with a small sample we can run ourselves. Thank you.