Tomcat 将 servlet 转换为 javax.servlet.Servlet 而不是 jakarta.servlet.http.HttpServlet [英] Tomcat casting servlets to javax.servlet.Servlet instead of jakarta.servlet.http.HttpServlet

查看:145
本文介绍了Tomcat 将 servlet 转换为 javax.servlet.Servlet 而不是 jakarta.servlet.http.HttpServlet的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试实现 tomcat 9 的 jakarta servlet,而不是以前的 javax.servlet 实现(因为我的理解是 jakarta 包是前进的方向).问题是,当我将浏览器指向 servlet 的 url 时,出现以下错误...

I have been trying in vain to implement tomcat 9's jakarta servlet as opposed to the previous javax.servlet implementation (as its my understanding that the jakarta package is the way forward). The issue is that when I point the browser at my servlet's url I get the following error(s)...

java.lang.ClassCastException: class cti.nm.web.Index cannot be cast to class javax.servlet.Servlet (cti.nm.web.Index is in unnamed module of loader org.apache.catalina.loader.ParallelWebappClassLoader @48c76607; javax.servlet.Servlet is in unnamed module of loader java.net.URLClassLoader @621be5d1)
    org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
    org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
    org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    org.apache.coyote.ajp.AjpProcessor.service(AjpProcessor.java:432)
    org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:888)
    org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
    org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    java.base/java.lang.Thread.run(Thread.java:832)

问题已经很明显了.Tomcat 正在尝试将我的 jakarta.servlet.http.HttpServlet 转换为 javax.servlet.Servlet,这显然不起作用.我想不通的是如何告诉它 servlet 实际实现的是哪个类.

The problem is obvious enough. Tomcat is trying to cast my jakarta.servlet.http.HttpServlet to a javax.servlet.Servlet which clearly won't work. What I can't figure is how to tell it what class the servlet is actually implementing.

类本身被声明为 ...

The class itself is declared as ...

package cti.nm.web;
import jakarta.servlet.http.HttpServlet;
import java.io.IOException;
import java.io.PrintWriter;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

public class Index extends HttpServlet {
     
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)
      throws IOException, ServletException {

        response.setContentType("text/html");
       //print a bunch of stuff
    }
}

我的web.xml文件如下...

My web.xml file is as follows ...

<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_5_0.xsd"
         version="5.0">
         
    <display-name>NMWeb</display-name>
    <description>
       NMWeb Description
    </description>

    <servlet>
        <servlet-name>Index</servlet-name>
        <servlet-class>cti.nm.web.Index</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>Index</servlet-name>
        <url-pattern>/NMWeb</url-pattern>
    </servlet-mapping>

</web-app>  

我曾希望在部署描述符中使用正确的 jakartaee xml 模式会导致使用正确的类,但显然不是.WAR 似乎包含正确的 jars ...

I had hoped that using the proper jakartaee xml schema in the deployment descriptor would cause the correct clases to be used but apparently not. The WAR seems to contain the proper jars ...

jakarta.jakartaee-api-9.0.0.jar
tomcat-el-api-10.0.0.jar
tomcat-servlet-api-10.0.0.jarjakarta.servlet-api-5.0.0.jar
tomcat-jsp-api-10.0.0.jar

jakarta.jakartaee-api-9.0.0.jar
tomcat-el-api-10.0.0.jar
tomcat-servlet-api-10.0.0.jar jakarta.servlet-api-5.0.0.jar
tomcat-jsp-api-10.0.0.jar

pom 被指定为 ...

The pom is specified as ...

<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>
  <groupId>cti.nm.NMWeb</groupId>
  <artifactId>NMWeb</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>

  <build>
    <sourceDirectory>src</sourceDirectory>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
      <plugin>
        <artifactId>maven-war-plugin</artifactId>
        <version>3.2.3</version>
        <configuration>
          <warSourceDirectory>WebContent</warSourceDirectory>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-api</artifactId>
      <version>[9.0.0,)</version>
      
    </dependency>
    <!-- https://mvnrepository.com/artifact/jakarta.servlet/jakarta.servlet-api -->
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>[5.0.0,)</version>
      
    </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jsp-api -->
        <dependency>
            <groupId>org.apache.tomcat</groupId>
            <artifactId>tomcat-jsp-api</artifactId>
            <version>[10.0.0,)</version>
       
        </dependency>
  </dependencies>
</project>

在网上搜索这个问题的答案已经有好几天了,我似乎找不到这个确切场景的任何其他实例.我应该提到这是我手动修改的 Eclipse 生成的对象.当我部署 war 文件时,使用 maven 和 eclipse 构建会生成相同的结果.

It's been days of searching the web for answers to this question and I can't seem to find any other instances of this exact scenario. I should mention that this is an eclipse generated probject that I have manually modified. Building with both maven and eclipse generates the same results when I deploy the war file.

推荐答案

您基本上是在 WAR 中实际包含 Tomcat 10.x 特定库,然后将 WAR 部署到 Tomcat 9.x.这根本不是正确的方法.此外,Tomcat 10.x 是第一个被 Jakartified 的版本,而不是 Tomcat 9.x.

You're basically physically including Tomcat 10.x specific libraries in WAR and then deploying the WAR to Tomcat 9.x. This is not the correct approach at all. Moreover, Tomcat 10.x was the first version to be Jakartified, not Tomcat 9.x.

对于基于 Servlet 4.0、JSP 2.3、EL 3.0、WS 1.1 和 JASIC 1.0 的 Tomcat 9.x,您应该使用 javax.* 导入和 整个strong> 部分应该最少看起来像:

For Tomcat 9.x, which is based on Servlet 4.0, JSP 2.3, EL 3.0, WS 1.1 and JASIC 1.0, you should use javax.* imports and the entire <dependencies> section should minimally look like:

<dependencies>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>4.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet.jsp</groupId>
        <artifactId>javax.servlet.jsp-api</artifactId>
        <version>2.3.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.el</groupId>
        <artifactId>javax.el-api</artifactId>
        <version>3.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.websocket</groupId>
        <artifactId>javax.websocket-api</artifactId>
        <version>1.1</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.security.enterprise</groupId>
        <artifactId>javax.security.enterprise-api</artifactId>
        <version>1.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

对于基于 Servlet 5.0、JSP 3.0、EL 4.0、WS 2.0 和 JASIC 2.0 的 Tomcat 10.x,您应该使用 jakarta.* 导入和 整个strong> 部分应该最少看起来像:

For Tomcat 10.x, which is based on Servlet 5.0, JSP 3.0, EL 4.0, WS 2.0 and JASIC 2.0, you should use jakarta.* imports and the entire <dependencies> section should minimally look like:

<dependencies>
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>5.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.servlet.jsp</groupId>
        <artifactId>jakarta.servlet.jsp-api</artifactId>
        <version>3.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.el</groupId>
        <artifactId>jakarta.el-api</artifactId>
        <version>4.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.websocket</groupId>
        <artifactId>jakarta.websocket-api</artifactId>
        <version>2.0.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>jakarta.security.enterprise</groupId>
        <artifactId>jakarta.security.enterprise-api</artifactId>
        <version>2.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

请注意, 为它们显式设置为 provided,这意味着 Maven 应该包含物理 JAR生成的 WAR 文件的 /WEB-INF/lib 中的文件(因为它已经由 Tomcat 本身提供了!).否则,您只会因运行时类路径中的重复类而导致运行时冲突.

Please note that the <scope> is explicitly set to provided for them, which means that Maven should not include the physical JAR files in /WEB-INF/lib of the generated WAR file (because it's already provided by Tomcat itself!). Otherwise you only end up in runtime conflicts caused by duplicate classes in the runtime classpath.

另请注意,Tomcat 不是 JEE 服务器,因此为 Tomcat 9.x 或 jakarta.platform:jakarta 导入 javax:javaee-apiTomcat 10.x 的 .jakartaee-api 是每个定义错误的.因为它允许您针对其他 JEE 组件(例如 JSF、JSTL、CDI、BV、EJB、JPA、JAX-RS、JSONB 等)编译您的代码,而 Tomcat 实际上并没有直接提供它们.Tomcat 仅提供开箱即用的 Servlet、JSP、EL、WS 和 JASIC,因此您只需声明它们在 pom.xml 中.

Please also note that Tomcat is not a JEE server and thus importing either javax:javaee-api for Tomcat 9.x or jakarta.platform:jakarta.jakartaee-api for Tomcat 10.x is per definition wrong. Because it will allow you to compile your code against other JEE components such as JSF, JSTL, CDI, BV, EJB, JPA, JAX-RS, JSONB, etc etc while Tomcat actually doesn't offer them out the box. Tomcat only offers Servlet, JSP, EL, WS and JASIC out the box, so you should only declare them in pom.xml.

例如JSTL需要按照如何安装JSTL?绝对uri:http://java.sun.com/jstl/core无法解析,需要按照如何通过Maven正确安装和配置JSF库?和CDI需要按照说明单独安装在如何在Tomcat上安装和使用CDI?

For example, JSTL needs to be installed separately as instructed in How to install JSTL? The absolute uri: http://java.sun.com/jstl/core cannot be resolved and JSF needs to be installed separately as instructed in How to properly install and configure JSF libraries via Maven? and CDI needs to be installed separately as instructed in How to install and use CDI on Tomcat?

如果您在为 Tomcat 开发代码的过程中非常清楚这个限制(即确保自己不会在没有先在 Tomcat 中实际安装它们的情况下意外使用例如 JSTL、CDI、BV、JPA 等),并且只想最小化 pom.xml 样板文件,那么您也可以使用 Tomcat 9.x 的这种最小化依赖项配置:

If you're however very well aware of this limitation during developing code for Tomcat (i.e. make sure yourself that you don't accidentally use e.g. JSTL, CDI, BV, JPA, etc without actually installing them in Tomcat first), and merely want to minimize pom.xml boilerplate, then you can also get away with this minimalist dependencies configuration for Tomcat 9.x:

<dependencies>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-web-api</artifactId>
        <version>8.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

或者对于 Tomcat 10.x:

Or this for Tomcat 10.x:

<dependencies>
    <dependency>
        <groupId>jakarta.platform</groupId>
        <artifactId>jakarta.jakartaee-web-api</artifactId>
        <version>9.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

另见:

  • Tomcat 版本
  • Java EE 到底是什么?
  • 这篇关于Tomcat 将 servlet 转换为 javax.servlet.Servlet 而不是 jakarta.servlet.http.HttpServlet的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆