java .lang.NullPointerException в Джакарте. xml .bind.ContextFinder.handleClassCastException - PullRequest
0 голосов
/ 06 мая 2020

Я новичок в создании приложений API для отдыха. Здесь я пытался сделать простой метод, возвращающий ответ xml объекта модели Message

Вот моя сеть. 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>

У меня есть класс обслуживания который возвращает жестко запрограммированный список объектов 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 возвращал ответ):

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 при попытке вернуть XML

Я использовал модификаторы для полей объекта модели должен быть частным, как было предложено. (используемый по умолчанию тип доступа XML jaxb может работать с частными полями)

Кто-нибудь может предложить это?

1 Ответ

0 голосов
/ 09 мая 2020

После многочисленных попыток решить эту проблему я получил решение:

Немного фонового сценария того, что вызывает java.lang.NullPointerException с отображением трассировки стека handleClassCastException при использовании JAXB, можно найти по адресу https://github.com/javaee/jaxb-v2/issues/863, происходит нечто подобное.

Итак, в основном, одновременно существовало более одной копии API для JAXB. В моем приложении Jakarta API был частью зависимости от jersey (Jakarta теперь является стандартным API для Java EE), но снова до JDK 8 JAXB также был частью расширенных API Java в пути к классам (поддержка javax). Я использовал jakarta api для импорта аннотаций и классов JAXB, но также использовал jdk 8 для компиляции, что вызвало проблему. Переходя к использованию трикотажа, я реализовал REST API с использованием pom-зависимости Jersey 3.0.0 (которая все еще «слишком нова», чтобы считаться стабильной версией).

Решением может быть использование javax для всех API и импорт, если вы собираетесь придерживаться JDK 8 - и понижение версии jersey в pom (я использовал 2.3.1) [или во внешней версии JAR, если вы не в maven)

Обратите внимание, что версия джерси более высокого уровня - 3.0.0 поставляется в комплекте только с API jakarta, и в таких случаях вам придется перенести импорт из javax в jakarta.

Второй вариант - если вы собираетесь обновить версию JDK выше, чем 1.8, вы должны получить NoClassDefFoundError, но это можно решить, если вы все еще используете версию JDK не выше 10. Jaxb API теперь должен быть API Java EE, а путь к классам не содержит их по умолчанию. Однако есть способ включить их: Как разрешить java .lang.NoClassDefFoundError: javax / xml / bind / JAXBException в Java 9

В моем случае я предоставил поддержка классов реализации JAXB путем записи в pom. xml:

Подводя итог, я сделал следующее:

  • Я продолжил использовать JDK 10 с jersey 2.3.1
  • обеспечил поддержку JAXB через добавленные зависимости в POM:
        <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>
...