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.