1

I have a very strange problem. I am creating a JPA (Eclipselink) application, with a Jersey rest service, and an angularJS front end.

When the application starts up, when I go to my angular page, I get a marshalling exception which seems to be caused by a null pointer somewhere. Press refresh in my browser, and the data comes back - no exceptions, and I am good to go from there on in.

I am using @XMLInverseReference on a one to many join, and the way I have set the annotations is the only way I can get parseable JSON with a back reference. It must be all set up correctly, as after the exception is raised the application works across Get, Post and Put so I have a workable CRUD interface.

Exception is:

WARNING: WebApplicationException cause: javax.xml.bind.MarshalException - with linked exception: [Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): 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:457) at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.writeTo(MOXyJsonProvider.java:840) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.invokeWriteTo(WriterInterceptorExecutor.java:243) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor.aroundWriteTo(WriterInterceptorExecutor.java:230) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149) at org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor.aroundWriteTo(JsonWithPaddingInterceptor.java:103) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149) at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundWriteTo(MappableExceptionWrapperInterceptor.java:88) at org.glassfish.jersey.message.internal.WriterInterceptorExecutor.proceed(WriterInterceptorExecutor.java:149) at org.glassfish.jersey.message.internal.MessageBodyFactory.writeTo(MessageBodyFactory.java:1139) at org.glassfish.jersey.server.ServerRuntime$Responder.writeResponse(ServerRuntime.java:557) at org.glassfish.jersey.server.ServerRuntime$Responder.processResponse(ServerRuntime.java:381) at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:371) at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:262) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) at org.glassfish.jersey.internal.Errors.process(Errors.java:315) at org.glassfish.jersey.internal.Errors.process(Errors.java:297) at org.glassfish.jersey.internal.Errors.process(Errors.java:267) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318) at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236) at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983) at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:176) at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145) at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92) at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:389) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:315) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:744) Caused by: Exception [EclipseLink-25003] (Eclipse Persistence Services - 2.5.1.v20130918-f2b9fc5): 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:98) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:897) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:862) at org.eclipse.persistence.jaxb.JAXBMarshaller.marshal(JAXBMarshaller.java:455) ... 50 more Caused by: java.lang.NullPointerException at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshal(XMLCompositeObjectMappingNodeValue.java:145) at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:102) at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:59) at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:401) at org.eclipse.persistence.internal.oxm.XPathObjectBuilder.buildRow(XPathObjectBuilder.java:240) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:118) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:1) at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshalSingleValue(XMLCompositeCollectionMappingNodeValue.java:328) at org.eclipse.persistence.internal.oxm.XMLCompositeCollectionMappingNodeValue.marshal(XMLCompositeCollectionMappingNodeValue.java:108) at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:149) at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:102) at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:59) at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:401) at org.eclipse.persistence.internal.oxm.XPathObjectBuilder.buildRow(XPathObjectBuilder.java:240) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:118) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:1) at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshalSingleValue(XMLCompositeObjectMappingNodeValue.java:249) at org.eclipse.persistence.internal.oxm.XMLCompositeObjectMappingNodeValue.marshal(XMLCompositeObjectMappingNodeValue.java:150) at org.eclipse.persistence.internal.oxm.NodeValue.marshal(NodeValue.java:102) at org.eclipse.persistence.internal.oxm.record.ObjectMarshalContext.marshal(ObjectMarshalContext.java:59) at org.eclipse.persistence.internal.oxm.XPathNode.marshal(XPathNode.java:401) at org.eclipse.persistence.internal.oxm.XPathObjectBuilder.buildRow(XPathObjectBuilder.java:240) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:118) at org.eclipse.persistence.internal.oxm.TreeObjectBuilder.buildRow(TreeObjectBuilder.java:1) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:751) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:571) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshalStreamOrWriter(XMLMarshaller.java:1107) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:1079) at org.eclipse.persistence.internal.oxm.XMLMarshaller.marshal(XMLMarshaller.java:892) ... 52 more

My "One" side of my JPA entity is:

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.PersistenceUnit;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

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

@Entity(name = "PR_GPT")
@Table
@XmlRootElement
@XmlType(propOrder={"id", "gptDesc", "therapyArea"})
@PersistenceUnit(unitName = "graps-jpa")
public class PrGPT {

    @ManyToOne
    @JoinColumn(name="THERAPY_AREA")
    @XmlInverseReference(mappedBy="gpts")   
    @XmlElement
    protected PrTherapyArea therapyArea;

    @Id
    @Column(name = "ID")    
    @GeneratedValue(generator = "prGPTSequence", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "prGPTSequence", sequenceName = "PR_GPT_SEQ", allocationSize=50)  
    @XmlElement
    private Long id;

    @Column(name = "GPT_DESC", length = 255)
    @Size(min = 1, max = 255)
    @XmlElement
    private String gptDesc;

    public void setTherapyArea(PrTherapyArea therapyArea) {
        this.therapyArea = therapyArea;     
    }


    public PrTherapyArea getTherapyArea() {
        return this.therapyArea;
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }


    public String getGptDesc() {
        return gptDesc;
    }

    public void setGptDesc(String gptDesc) {
        this.gptDesc = gptDesc;
    }

    public PrGPT() {
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("GPT [");
        sb.append("GPT ID : ").append(id).append(", GPT Desc : ")
                .append(gptDesc).append("]");
        return sb.toString();
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((this.getId() == null) ? 0 : this.getId().hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PrGPT other = (PrGPT) obj;
        if (this.getId() == null) {
            if (other.getId() != null)
                return false;
        } else if (this.getId().compareTo(other.getId()) != 0)
            return false;
        return true;
    }

}

My many side is as below:

@Entity(name = "PR_THERAPY_AREA")
@Table
@XmlRootElement
@PersistenceUnit(unitName = "graps-jpa")
public class PrTherapyArea {



    @Id
    @Column(name = "ID")
    @GeneratedValue(generator = "prTASequence", strategy = GenerationType.SEQUENCE)
    @SequenceGenerator(name = "prTASequence", sequenceName = "PR_TA_SEQ", allocationSize=50)    
    @XmlElement 
    private Long id;

    @Column(name = "THERAPY_AREA", length = 255)
    @Size(min = 1, max = 255)
    @XmlElement 
    private String therapyArea;


    public Long getId() {
        return id;
    }


    @OneToMany(mappedBy="therapyArea", orphanRemoval = true, cascade = { javax.persistence.CascadeType.PERSIST, javax.persistence.CascadeType.MERGE }, fetch = FetchType.EAGER)
    @XmlElement     
    protected List<PrGPT> gpts;

    public void setId(Long id) {
        this.id = id;
    }


    public List<PrGPT> getGpts() {
        return this.gpts;
    }

    public void setGpts(List<PrGPT> gpts) {
        this.gpts = gpts;
    }


    public String getTherapyArea() {
        return therapyArea;
    }

    public String setTherapyArea() {
        return therapyArea;
    }

    public PrTherapyArea() {
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("THERAPY AREA [");
        sb.append("THERAPY_AREA ID : ").append(id)
                .append(", Therapy Area Desc : ").append(therapyArea)
                .append("]");
        return sb.toString();
    }


    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((this.getId() == null) ? 0 : this.getId().hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        PrTherapyArea other = (PrTherapyArea) obj;
        if (this.getId() == null) {
            if (other.getId() != null)
                return false;
        } else if (this.getId().compareTo(other.getId()) != 0)
            return false;
        return true;
    }


}

I tried without adding @XMLInverseReference on the many side in TherapyArea back to GPT, but the JSON is badly formed (I raised a SO question on this but didn't get a response unfortunately @XmlInverseReference - invalid token in json in a bidirectional JPA relationship and this is the only way to get a good json response).

My json response is fine, with the back reference i need to the TherapyArea through @XMLInverseReference:

GPT Get response:

[{"id":1452,"gptDesc":"testing 1-2-3","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":1454,"gptDesc":"test 99","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1456,"gptDesc":"testing 1-2-3","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":1457,"gptDesc":"steves GPTss","therapyArea":{"id":5,"therapyArea":"Immuno-Oncology"}},{"id":1459,"gptDesc":"Debs GPT","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":1460,"gptDesc":"testing","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":1465,"gptDesc":"Test Add 3","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1466,"gptDesc":"Test Add 4","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1951,"gptDesc":"Test Add 56666666666666666666","therapyArea":{"id":1,"therapyArea":"Oncology"}},{"id":1952,"gptDesc":"Test Add 6","therapyArea":{"id":4,"therapyArea":"Respiratory and Inflammation"}},{"id":2002,"gptDesc":"Test add 9","therapyArea":{"id":1,"therapyArea":"Oncology"}},{"id":2003,"gptDesc":"test add 11","therapyArea":{"id":1,"therapyArea":"Oncology"}},{"id":2004,"gptDesc":"test add 12","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":2005,"gptDesc":"test","therapyArea":{"id":1,"therapyArea":"Oncology"}},{"id":2006,"gptDesc":"test","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":2007,"gptDesc":"test","therapyArea":{"id":2,"therapyArea":"Infection"}},{"id":2008,"gptDesc":"test","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":2009,"gptDesc":"Test","therapyArea":{"id":1,"therapyArea":"Oncology"}},{"id":2010,"gptDesc":"test","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":2012,"gptDesc":"Test","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1451,"gptDesc":"Testing1234567890909pp","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1453,"gptDesc":"testing 123456","therapyArea":{"id":3,"therapyArea":"CVMD"}},{"id":1455,"gptDesc":"Test 1012","therapyArea":{"id":4,"therapyArea":"Respiratory and Inflammation"}}]

Therapy Areas response:

[{"id":1,"therapyArea":"Oncology","gpts":[{"id":1951,"gptDesc":"Test Add 56666666666666666666"},{"id":2002,"gptDesc":"Test add 9"},{"id":2003,"gptDesc":"test add 11"},{"id":2005,"gptDesc":"test"},{"id":2009,"gptDesc":"Test"}]},{"id":2,"therapyArea":"Infection","gpts":[{"id":1452,"gptDesc":"testing 1-2-3"},{"id":1456,"gptDesc":"testing 1-2-3"},{"id":1459,"gptDesc":"Debs GPT"},{"id":1460,"gptDesc":"testing"},{"id":2004,"gptDesc":"test add 12"},{"id":2006,"gptDesc":"test"},{"id":2007,"gptDesc":"test"}]},{"id":3,"therapyArea":"CVMD","gpts":[{"id":1454,"gptDesc":"test 99"},{"id":1465,"gptDesc":"Test Add 3"},{"id":1466,"gptDesc":"Test Add 4"},{"id":2008,"gptDesc":"test"},{"id":2010,"gptDesc":"test"},{"id":2012,"gptDesc":"Test"},{"id":1451,"gptDesc":"Testing1234567890909pp"},{"id":1453,"gptDesc":"testing 123456"}]},{"id":4,"therapyArea":"Respiratory and Inflammation","gpts":[{"id":1952,"gptDesc":"Test Add 6"},{"id":1455,"gptDesc":"Test 1012"}]},{"id":5,"therapyArea":"Immuno-Oncology","gpts":[{"id":1457,"gptDesc":"steves GPTss"}]}]

I have a jaxb.properties file set up in the same package as my entity models as I know I need to.

Don't really understand what is going on.

I don't think it has anything to do with caching on the client, which was suggested by a colleague. Could be I guess, but I suspect it's more to do with the @XmlInverseReference.

UPDATE:

On application restart, going straight for the rest end point url, I get a response for both entities, without an exception being raised. Then when I go to the angular page, the exception doesnt get raised.

Go to my crud page as the first action after an app restart, I get the marshalling exception, refresh then it is fine.

Almost like I need to "prime" it before it will work?! But going to the restful endpoint has nothing to do with angular, its a pure jersey response....

UPDATE 2:

This seems to resolve the error:

//call the TA service to get the TA list for the drop down lists
            prTAService.getTAs().then(function(tas) {
                $scope.therapyAreas = tas;
                prGPTService.getGPTs().then(function(gpts) {
                    $scope.prGpts = gpts;
                });
            });

i.e. only get one set of resources, after the first set of resources has loaded.....i.e. a then inside a then!? Seems odd.

Community
  • 1
  • 1
smackenzie
  • 2,880
  • 7
  • 46
  • 99

1 Answers1

1

I've seen this before when JAXB is first instantiated concurrently. There are some race conditions where it fails to initialize properly if it's started from multiple threads. I can imagine that happening from an angular page that made simultaneous backend calls.

Not a lot you can do apart from hit the endpoint once from curl (or whatever) before using the browser.

artbristol
  • 32,010
  • 5
  • 70
  • 103
  • Hi, thanks. so I cant build a restful application in angular and jersey? How can I force my application to hit the endpoint for all users to prime jaxb from the application side? I can't have an application which doesnt work unless the user hits refresh after initial load. – smackenzie Sep 17 '14 at 15:02
  • Is there not a way to prime JAXB on application startup at the backend? – smackenzie Sep 17 '14 at 15:30
  • You could add some kind of initialization listener. The problem should only occur for the first user to hit the application, not once per user. (Of course, my answer might turn out not to be relevant) – artbristol Sep 18 '14 at 09:49
  • I tried to add a manual unmarshalling of some entities in my AppInitiatlier class I have created, but I was getting Cyclic errors despite setting @XMLInverseReference, and despite not getting cyclic errors in the main app...so I made some objects which dont have back references to each other, and manually marshalled them when the application initialises...I see the XML output in the console, so I know it is working...but the error still presents itself in the application. – smackenzie Sep 18 '14 at 16:37
  • 1
    I suspect it is to do with angular firing off 2 asynchronous requests close together, as the issue has gone away when I nest my async calls....bit worrying though. – smackenzie Sep 18 '14 at 16:37