我使用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.xml
和module-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;
}
1条答案
按热度按时间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>
)。