升级Jetty与Jakarta包后出现UnavailableException问题求助
问题:升级Jetty和Jakarta包后抛出Servlet类型不匹配异常
将插件页面提供的示例更新到最新版Jetty容器和Jakarta包后抛出异常,程序期望旧类javax.servlet.Servlet,而非新的jakarta.servlet.Servlet。
环境信息
os: Ubuntu 22.10 java: openjdk version "11.0.11" 2021-04-20 scala: 2.13.10
build.sbt配置
ThisBuild / version := "0.1.0-SNAPSHOT" ThisBuild / scalaVersion := "2.13.10" lazy val root = (project in file(".")) .settings( name := "MyServlet" ) val jakartaServletApiVersion = "6.0.0" val jettyVersion = "11.0.13" libraryDependencies += "jakarta.servlet" % "jakarta.servlet-api" % jakartaServletApiVersion Jetty / containerLibs := Seq("org.eclipse.jetty" % "jetty-runner" % jettyVersion) enablePlugins(JettyPlugin)
plugins.sbt配置
addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "4.2.4")
web.xml配置
<servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>mypackage.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping>
MyServlet.scala代码
package mypackage import jakarta.servlet.annotation.WebServlet import jakarta.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse} @WebServlet(urlPatterns = Array("/hello")) class MyServlet extends HttpServlet { println("HEY") override def doGet(req: HttpServletRequest, res: HttpServletResponse): Unit = { res.setContentType("text/html") res.setCharacterEncoding("UTF-8") res.getWriter.write("""<h1>Hello, world!</h1>""") } }
执行命令
jetty:start
抛出异常
UnavailableException: Servlet class mypackage.MyServlet is not a javax.servlet.Servlet
javax.servlet.UnavailableException: Servlet class mypackage.MyServlet is not a javax.servlet.Servlet at org.eclipse.jetty.servlet.ServletHolder.checkServletType(ServletHolder.java:514) at org.eclipse.jetty.servlet.ServletHolder.doStart(ServletHolder.java:386) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) at org.eclipse.jetty.servlet.ServletHandler.lambda$initialize$0(ServletHandler.java:730) at java.base/java.util.stream.SortedOps$SizedRefSortingSink.end(SortedOps.java:357) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:485) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:312) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658) at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:755) at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:379) at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1449) at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1414) at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:911) at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:288) at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:524) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:117) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:169) at org.eclipse.jetty.server.Server.start(Server.java:423) at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:110) at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:97) at org.eclipse.jetty.server.Server.doStart(Server.java:387) at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73) at org.eclipse.jetty.runner.Runner.run(Runner.java:519) at org.eclipse.jetty.runner.Runner.main(Runner.java:564)
原因分析与解决方法
原因
你使用的xsbt-web-plugin 4.2.4版本默认适配传统javax.servlet规范,未支持Jakarta EE的包名迁移(从javax改为jakarta)。尽管Jetty 11本身兼容Jakarta Servlet 5.0/6.0,但插件仍在用旧的javax.servlet.Servlet类型校验你的Servlet类,导致类型不匹配异常。
解决步骤
升级xsbt-web-plugin到支持Jakarta的版本
修改plugins.sbt中的插件版本为5.x系列(要求sbt 1.5+,你的环境满足):addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "5.0.0")在build.sbt中启用Jakarta模式
添加配置告知插件使用Jakarta Servlet规范:webAppPackage := WebAppPackage.Jakarta更新web.xml的Jakarta命名空间
将旧的javax命名空间替换为Jakarta EE 6.0规范:<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd" version="6.0"> <servlet> <servlet-name>MyServlet</servlet-name> <servlet-class>mypackage.MyServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>MyServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> </web-app>
完成以上修改后,重新执行jetty:start即可正常启动服务。
内容的提问来源于stack exchange,提问作者Heitor Barbieri
相关产品推荐
相关产品推荐

