【问题标题】:NPE Thrown Marshalling Entity in JAX-RSJAX-RS 中 NPE 抛出的编组实体
【发布时间】:2011-03-19 19:30:23
【问题描述】:

我有一个使用 JPA 实体类的 JAX-RS Web 服务。我有一个这样的资源类:

@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;
    }
}

当我运行服务并对实体进行 get 调用时,我收到此错误:

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 或如何调试它。

在此错误之前,我从我的 JPA (EclipseLink) 实体类中获得了 [com.sun.istack.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML:,并在父 getter 方法上将注释 MOXy @XmlInverseReference 添加到我的子类中。

有什么想法会引发这个异常吗?

【问题讨论】:

    标签: jpa jaxb eclipselink jax-rs moxy


    【解决方案1】:

    我们已经就这个问题进行了一些离线讨论,为了其他人的利益,发现下面这篇文章是在多个级别使用 @XmlInverseReference 的正确设置:

    实体 A

    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;
        }
    
    }
    

    实体 B

    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;
        }
    }
    

    实体 C

    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 论坛也正在处理此问题,有关更多信息,请参阅:

    下面是另一个使用 JPA 模型的 @XmlInverseReference 示例

    【讨论】:

    • 除上述之外,NPE 是由为空的孙类/元素上的时间戳字段引起的。我扩展了 XmlAdapter 来处理时间戳的编组,这引发了 NPE。
    【解决方案2】:

    您是否在实体类中包含了 jaxb.properties 文件?

    查看 Blaise 对此问题的回答:JAXB Mapping cyclic references to XML

    希望这会有所帮助。 RG

    【讨论】:

    • 从堆栈跟踪来看,jaxb.properties 文件似乎就位。
    • 感谢您的回复。是的,我有一个包含以下内容的 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 注释的地方。
    猜你喜欢
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 2014-03-12
    • 2016-08-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多