java 使用模块系统时嵌入式Jetty中出现ClassNotFoundException

a64a0gku  于 2023-01-07  发布在  Java
关注(0)|答案(1)|浏览(208)

我使用Jersey(3.1.0)的嵌入式Jetty(11.0.13)服务器,Jersey(3.1.0)提供了一个简单的REST接口,该接口返回JSON对象,JSON对象使用Jackson序列化。
只要我不使用Java的模块系统,安装程序就能正常工作。但是当我添加module-info.java文件(见下文)时,我一调用服务就会得到以下错误。

WARNING: The following warnings have been detected: WARNING: Unknown HK2 failure detected:
MultiException stack 1 of 2
java.lang.NoClassDefFoundError: jakarta/xml/bind/annotation/XmlElement
    at com.fasterxml.jackson.module.jakarta.xmlbind.JakartaXmlBindAnnotationIntrospector.<init>(JakartaXmlBindAnnotationIntrospector.java:137)
    ...
Caused by: java.lang.ClassNotFoundException: jakarta.xml.bind.annotation.XmlElement
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
    ... 83 more
MultiException stack 2 of 2
java.lang.IllegalStateException: Unable to perform operation: post construct on org.glassfish.jersey.jackson.internal.DefaultJacksonJaxbJsonProvider
    at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:429)
    at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:466)
    ...

为了使它工作,我必须将JAX-B-API添加到pom.xmlmodule-info.java中。只有在使用Java模块时才会出现错误。当我简单地删除module-info.java文件时,everythink即使没有JAX-B依赖也能正常工作。
这就是我真正困惑的地方。为什么当我使用模块系统时需要JAX-B依赖关系,而当我不使用它时却不需要?为什么会出现ClassNotFoundException?启动时不应该警告模块系统缺少依赖关系吗?
我希望有人能解释一下。我花了好几天才弄明白。
这是产生问题的设置:

    • 聚合物. xml**
<project>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.target>17</maven.compiler.target>
        <maven.compiler.source>17</maven.compiler.source>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>11.0.13</version>
        </dependency>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>11.0.13</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.inject</groupId>
            <artifactId>jersey-hk2</artifactId>
            <version>3.1.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-json-jackson</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
</project>
    • 主要. java**
public class Main {
    public static void main(String[] args) throws Exception {
        Server server = new Server(8080);
        server.setStopAtShutdown(true);
    
        ServletContextHandler context = new ServletContextHandler(server, "/");
        ServletHolder servletHolder = context.addServlet(ServletContainer.class, "/*");
        servletHolder.setInitParameter("jersey.config.server.provider.packages", "com.example.demo");
        servletHolder.setInitParameter("jersey.config.server.wadl.disableWadl", "true");
        
        server.start();
    }
}
    • 演示资源. java**
@Path("/hello")
public class DemoResource {
    @GET
    @Produces("application/json")
    public HelloDto hello() {
        return new HelloDto("Hello, World!");
    }
    
    public record HelloDto(String value) {
        @JsonGetter("value")
        public String value() {
            return this.value;
        }
    }
}
    • 模块信息. java**
module demo {
    requires org.eclipse.jetty.server;
    requires org.eclipse.jetty.servlet;
    requires jersey.container.servlet.core;
    requires jakarta.ws.rs;
    requires com.fasterxml.jackson.annotation;
}
mefy6pfw

mefy6pfw1#

这是类路径(旧式Java)和模块路径(新式Java平台模块系统,又名JPMS)的标准JVM行为。
一旦您有了module-info.class,您就有了一个活动的modulepath,以及它所具有的所有访问规则。
您的运行库可以同时拥有这两者,这是很正常的。
不要依赖老式的类路径来绕过坏代码和坏行为,使用JPMS和module-info.class,您将知道这些项目jar的开发人员打算让您使用什么(例如,您将不被允许使用内部类,因为这些类非常不稳定,可能随时更改)。
jakarta.xml.bind是HK2运行所必需的,因此您必须在构建依赖项中声明它才能编译,然后您的module-info.java才能访问它。
查看Stackoverflow上的其他答案,以获得如何正确使用module-info.java的建议(不仅仅是requires <module>)。

相关问题