NPE бросил маршалинговый объект в JAX-RS

У меня есть веб-сервис JAX-RS, который использует классы сущностей JPA. У меня есть такой класс ресурсов:

@Path("/entity")
public class MyEntityResource
{
    @GET
    @Produces(MediaType.APPLICATION_XML)
    @Path("/{entity}")
    public MyEntity getMyEntity(@PathParam("entity") String entity)
    {
        log.debug("Entering getMyEntity with param: " + entity);
        MyEntity entityObject = genericService.find(MyEntity.class, entity);

        if (entityObject == null)
        {
            log.debug("Entity not found.");
            throw new WebApplicationException(Response.Status.NOT_FOUND);
        }

        log.debug("Exiting getMyEntity");

        return entityObject;
    }
}

Когда я запускаю службу и выполняю вызов объекта, я получаю эту ошибку:

SEVERE: The response of the WebApplicationException cannot be utilized as the response is already committed. Re-throwing to the HTTP container
javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException
 - with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException]
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:151)
... 
<snip>
... 
Caused by: javax.xml.bind.MarshalException
 - with linked exception:
[Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException]
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:271)
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:171)
    at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.writeTo(AbstractRootElementProvider.java:149)
    ... 32 more
Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.XMLMarshalException
Exception Description: An error occurred marshalling the object
Internal Exception: java.lang.NullPointerException
    at org.eclipse.persistence.exceptions.XMLMarshalException.marshalException(XMLMarshalException.java:76)
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:502)
    at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:269)
    ... 34 more
Caused by: java.lang.NullPointerException
    at org.eclipse.persistence.exceptions.ConversionException.couldNotBeConverted(ConversionException.java:69)
... 
<snip>
... 
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:916)
    at org.eclipse.persistence.oxm.XMLMarshaller.marshal(XMLMarshaller.java:468)
    ... 35 more

Нигде ни в одной из трассировок стека не упоминается ни один из моих классов. Кроме того, оператор "Exiting getMyEntity" регистрируется перед исключением.

Я понятия не имею, что вызывает NPE или как это отлаживать.

До этой ошибки я получал [com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: из своих классов сущностей JPA (EclipseLink) и добавлял аннотацию MOXy @XmlInverseReference к моему дочернему классу в родительском методе получения.

Любые мысли о том, что может вызывать это исключение?


person sdoca    schedule 22.07.2010    source источник


Ответы (2)


У нас было некоторое автономное обсуждение этой проблемы, и в интересах других, которые найдут этот пост ниже, это правильная настройка использования @XmlInverseReference на нескольких уровнях:

Объект А

import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import java.util.Set;

@Entity
@XmlRootElement
public class EntityA implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Set<EntityB> entityBs;

    @Id
    @XmlAttribute
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @OneToMany(mappedBy = "entityABean")
    @XmlElement
    public Set<EntityB> getEntityBs() {
        return this.entityBs;
    }

    public void setEntityBs(Set<EntityB> entityBs) {
        this.entityBs = entityBs;
    }

}

Объект Б

import java.io.Serializable;
import javax.persistence.*;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.eclipse.persistence.oxm.annotations.XmlInverseReference;

import java.util.Set;

@Entity
@XmlRootElement
public class EntityB implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Set<EntityC> entityCs;
    private EntityA entityABean;

    @Id
    @XmlAttribute
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToOne
    @JoinColumn(name = "EntityA")
    @XmlInverseReference(mappedBy = "entityBs")
    public EntityA getEntityABean() {
        return this.entityABean;
    }

    public void setEntityABean(EntityA entityABean) {
        this.entityABean = entityABean;
    }

    @OneToMany(mappedBy = "entityBBean")
    @XmlElement
    public Set<EntityC> getEntityCs() {
        return this.entityCs;
    }

    public void setEntityCs(Set<EntityC> entityCs) {
        this.entityCs = entityCs;
    }
}

Объект С

import java.io.Serializable;
import javax.persistence.*;

import org.eclipse.persistence.oxm.annotations.XmlInverseReference;

@Entity
public class EntityC implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private EntityB entityBBean;

    @Id
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ManyToOne
    @JoinColumn(name = "EntityB")
    @XmlInverseReference(mappedBy = "entityCs")
    public EntityB getEntityBBean() {
        return this.entityBBean;
    }

    public void setEntityBBean(EntityB entityBBean) {
        this.entityBBean = entityBBean;
    }
}

Демо

import java.io.FileInputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(EntityA.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        FileInputStream xml = new FileInputStream("src/test/jaxb/input.xml");
        EntityA a = (EntityA) unmarshaller.unmarshal(xml);

        for(EntityB b : a.getEntityBs()) {
            System.out.println(b.getEntityABean());
            for(EntityC c : b.getEntityCs()) {
                System.out.println(c.getEntityBBean());
            }
        }
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(a, System.out);
    }

}

Демонстрация – вывод

test.jaxb.EntityA@1292d26
test.jaxb.EntityB@196c1b0
test.jaxb.EntityB@196c1b0
test.jaxb.EntityA@1292d26
test.jaxb.EntityB@1e13d52
test.jaxb.EntityB@1e13d52

ввод.xml

<?xml version="1.0" encoding="UTF-8"?>
<entityA>
   <entityBs>
      <entityCs/>
      <entityCs/>
   </entityBs>
   <entityBs>
      <entityCs/>
      <entityCs/>
   </entityBs>
</entityA>

Эта проблема также решается на форумах EclipseLink, для получения дополнительной информации см.:

Ниже приведен еще один пример использования @XmlInverseReference с моделью JPA.

person bdoughan    schedule 26.07.2010
comment
В дополнение к вышеизложенному, NPE был вызван полем Timestamp для дочернего класса/элемента, который был нулевым. Я расширил XmlAdapter для обработки сортировки временных меток, и это вызвало NPE. - person sdoca; 30.07.2010

Вы включили файл jaxb.properties в свои классы сущностей?

Ознакомьтесь с ответом Блейза на этот вопрос: JAXB Mapping циклических ссылок на XML

Надеюсь это поможет. РГ

person Jordan Allan    schedule 22.07.2010
comment
Судя по трассировке стека, файл jaxb.properties находится на месте. - person bdoughan; 23.07.2010
comment
Спасибо за ответ. Да, у меня есть файл jaxb.properties со следующим содержимым: # Укажите, что следует использовать реализацию EclipseLink MOXy JAXB javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory Я считаю, что он трассировка стека относится к: org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:271). Я видел другой пост, в котором я узнал о MOXy и аннотации @XmlInverseReference, которую я использовал в своем коде. - person sdoca; 23.07.2010