java.lang.NullPointerException 在 jakarta.xml.bind.ContextFinder.handleClassCastException
java.lang.NullPointerException at jakarta.xml.bind.ContextFinder.handleClassCastException
我对构建 rest API 应用程序还很陌生。在这里,我试图制作一个简单的方法 return 模型对象 Message
的响应 xml
这是我的 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.rest.messenger.service</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>
我有一项服务 class,其中 return 是 Message
对象的硬编码列表。
package com.rest.messenger.service;
import java.util.ArrayList;
import java.util.List;
import com.rest.messenger.model.Message;
public class MessageService {
public List<Message> getAllMessages(){
Message m1 = new Message(1L, "message1", "mt");
Message m2 = new Message( 2L, "message 2", "pt");
List<Message> messages = new ArrayList<Message>();
messages.add(m1);
messages.add(m2);
return messages;
}
}
Message
对象定义如下(这里我使用 @XmlRootElement
注解让 jaxb 将其转换为 xml,因为我想要一个 xml 响应return按资源编辑):
package com.rest.messenger.model;
import java.util.Date;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Message {
private long id;
private String message;
private String author;
private Date created;
public Message() {
}
public Message(long id, String message, String author) {
super();
this.id = id;
this.message = message;
this.author = author;
this.created = new Date();
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
}
我将传入的 GET
请求映射到资源,如下所示:
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/messages")
public class MessageResource {
public MessageService messageService = new MessageService();
@GET
@Produces(MediaType.APPLICATION_XML)
public List<Message> getMessages() {
return messageService.getAllMessages();
}
}
现在,当我 运行 尝试访问位于 URL http://localhost:8080/messenger.service/webapi/messages
的资源时
我收到以下内部服务器错误:
May 06, 2020 1:28:14 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/messenger.service] threw exception [java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at jakarta.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:114)
at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:254)
at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:240)
at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:375)
at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:691)
at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:632)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getStoredJaxbContext(AbstractJaxbProvider.java:288)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getJAXBContext(AbstractJaxbProvider.java:273)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:240)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:207)
at org.glassfish.jersey.jaxb.internal.AbstractCollectionJaxbProvider.writeTo(AbstractCollectionJaxbProvider.java:243)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:242)
我遵循的教程使用了 javax,我相信它现在已迁移到雅加达。
不确定它是否与@XmlRootElement 有关
我还按照以下建议在 pom.xml
中添加了依赖项:
jersey return 500 when trying return an XML
我按照建议将模型对象字段的修饰符设为私有。(使用的默认 XML 访问器类型 jaxb 能够在私有字段上工作)
任何人都可以对此提出建议吗?
经过多次尝试解决这个问题,我得到了解决方案:
在使用 JAXB
时堆栈跟踪显示 handleClassCastException
时导致 java.lang.NullPointerException
的一些背景情况可以在 https://github.com/javaee/jaxb-v2/issues/863 找到类似的事情。
所以基本上,JAXB 的 APIs 一次有多个副本。我的应用程序将 Jakarta API 作为 jersey 依赖项的一部分(Jakarta 现在是 Java EE 的标准 API)但是直到 JDK 8,JAXB 也是 [=42 的一部分=] 在类路径中扩展 APIs(javax 支持)。我使用 jakarta api 导入 JAXB 注释和 类,但也使用 jdk 8 进行编译,因此导致了问题。开始使用球衣,我正在使用 Jersey 3.0.0 的 pom 依赖项实现 REST API(仍然 "too new" 被认为是稳定版本)
如果您要坚持使用 JDK 8,解决方案可能是对所有 api 和导入使用 javax - 并在 pom
中降级球衣版本(我使用 2.3 .1) [ 或者外部 JAR 版本,如果你不在 maven 上)
请注意,更高版本的 jersey 版本 - 3.0.0 仅与 jakarta APIs 捆绑在一起,在这种情况下,您需要将导入从 javax 转移到 jakarta。
第二个选项是,如果您打算将 JDK 版本升级到高于 1.8,您应该得到 NoClassDefFoundError
,但如果您仍在使用 JDK,则可以解决版本不大于 10。Jaxb API 现在应该是 Java EE 的 API,默认情况下类路径不包含它们。然而,有一种方法可以启用它们:
就我而言,我通过在 pom.xml:
中输入来为 JAXB 实现 类 提供支持
总而言之,我做了以下事情:
- 我继续使用 JDK 10 球衣 2.3.1
- 通过在 POM 中添加依赖项提供了对 JAXB 的支持:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
<scope>runtime</scope>
</dependency>
我对构建 rest API 应用程序还很陌生。在这里,我试图制作一个简单的方法 return 模型对象 Message
这是我的 web.xml
<?xml version="1.0" encoding="UTF-8"?>
<!-- This web.xml file is not required when using Servlet 3.0 container,
see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.rest.messenger.service</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey Web Application</servlet-name>
<url-pattern>/webapi/*</url-pattern>
</servlet-mapping>
</web-app>
我有一项服务 class,其中 return 是 Message
对象的硬编码列表。
package com.rest.messenger.service;
import java.util.ArrayList;
import java.util.List;
import com.rest.messenger.model.Message;
public class MessageService {
public List<Message> getAllMessages(){
Message m1 = new Message(1L, "message1", "mt");
Message m2 = new Message( 2L, "message 2", "pt");
List<Message> messages = new ArrayList<Message>();
messages.add(m1);
messages.add(m2);
return messages;
}
}
Message
对象定义如下(这里我使用 @XmlRootElement
注解让 jaxb 将其转换为 xml,因为我想要一个 xml 响应return按资源编辑):
package com.rest.messenger.model;
import java.util.Date;
import jakarta.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Message {
private long id;
private String message;
private String author;
private Date created;
public Message() {
}
public Message(long id, String message, String author) {
super();
this.id = id;
this.message = message;
this.author = author;
this.created = new Date();
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
}
我将传入的 GET
请求映射到资源,如下所示:
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
@Path("/messages")
public class MessageResource {
public MessageService messageService = new MessageService();
@GET
@Produces(MediaType.APPLICATION_XML)
public List<Message> getMessages() {
return messageService.getAllMessages();
}
}
现在,当我 运行 尝试访问位于 URL http://localhost:8080/messenger.service/webapi/messages
我收到以下内部服务器错误:
May 06, 2020 1:28:14 PM org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/messenger.service] threw exception [java.lang.NullPointerException] with root cause
java.lang.NullPointerException
at jakarta.xml.bind.ContextFinder.handleClassCastException(ContextFinder.java:114)
at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:254)
at jakarta.xml.bind.ContextFinder.newInstance(ContextFinder.java:240)
at jakarta.xml.bind.ContextFinder.find(ContextFinder.java:375)
at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:691)
at jakarta.xml.bind.JAXBContext.newInstance(JAXBContext.java:632)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getStoredJaxbContext(AbstractJaxbProvider.java:288)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getJAXBContext(AbstractJaxbProvider.java:273)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:240)
at org.glassfish.jersey.jaxb.internal.AbstractJaxbProvider.getMarshaller(AbstractJaxbProvider.java:207)
at org.glassfish.jersey.jaxb.internal.AbstractCollectionJaxbProvider.writeTo(AbstractCollectionJaxbProvider.java:243)
at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:242)
我遵循的教程使用了 javax,我相信它现在已迁移到雅加达。
不确定它是否与@XmlRootElement 有关
我还按照以下建议在 pom.xml
中添加了依赖项:
jersey return 500 when trying return an XML
我按照建议将模型对象字段的修饰符设为私有。(使用的默认 XML 访问器类型 jaxb 能够在私有字段上工作)
任何人都可以对此提出建议吗?
经过多次尝试解决这个问题,我得到了解决方案:
在使用 JAXB
时堆栈跟踪显示 handleClassCastException
时导致 java.lang.NullPointerException
的一些背景情况可以在 https://github.com/javaee/jaxb-v2/issues/863 找到类似的事情。
所以基本上,JAXB 的 APIs 一次有多个副本。我的应用程序将 Jakarta API 作为 jersey 依赖项的一部分(Jakarta 现在是 Java EE 的标准 API)但是直到 JDK 8,JAXB 也是 [=42 的一部分=] 在类路径中扩展 APIs(javax 支持)。我使用 jakarta api 导入 JAXB 注释和 类,但也使用 jdk 8 进行编译,因此导致了问题。开始使用球衣,我正在使用 Jersey 3.0.0 的 pom 依赖项实现 REST API(仍然 "too new" 被认为是稳定版本)
如果您要坚持使用 JDK 8,解决方案可能是对所有 api 和导入使用 javax - 并在 pom
中降级球衣版本(我使用 2.3 .1) [ 或者外部 JAR 版本,如果你不在 maven 上)
请注意,更高版本的 jersey 版本 - 3.0.0 仅与 jakarta APIs 捆绑在一起,在这种情况下,您需要将导入从 javax 转移到 jakarta。
第二个选项是,如果您打算将 JDK 版本升级到高于 1.8,您应该得到 NoClassDefFoundError
,但如果您仍在使用 JDK,则可以解决版本不大于 10。Jaxb API 现在应该是 Java EE 的 API,默认情况下类路径不包含它们。然而,有一种方法可以启用它们:
就我而言,我通过在 pom.xml:
中输入来为 JAXB 实现 类 提供支持总而言之,我做了以下事情:
- 我继续使用 JDK 10 球衣 2.3.1
- 通过在 POM 中添加依赖项提供了对 JAXB 的支持:
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.1</version>
<scope>runtime</scope>
</dependency>