javarestbindingjaxbsaxparseexception

javax.xml.bind.UnmarshalException - with linked exception: [org.xml.sax.SAXParseException: Content is not allowed in prolog.]


Customer.java

@Entity
@Table(name = "CUSTOMER", uniqueConstraints =
{
 @UniqueConstraint(columnNames =
{
    "CUSTNO"
})
})
@XmlRootElement
public class Customer
    implements Serializable
{
/**
 * 
 */
private static final long serialVersionUID = 1L;

@Id @Column(name = "CUSTNO", length = 10, nullable = false) private String            custNo;

@Column(name = "TITLE", length = 20, nullable = false) private String                 title;

@Column(name = "FIRSTNAME", length = 20, nullable = false) private String             
firstName;

@Column(name = "MIDINIT", length = 1, nullable = true) private String                 
midInit;

@Column(name = "LASTNAME", length = 1, nullable = false) private String               
lastName;

@Column(name = "EMAIL", length = 50, nullable = false) private String                 
email;

@Column(name = "PHONE", length = 16, nullable = true) private String                  
phone;

@Column(name = "GENDER", length = 1, nullable = true) private String                  
gender;

@Column(name = "STREETADDRESS", length = 50, nullable = true) private String          
streetAddress;

@Column(name = "CITY", length = 20, nullable = true) private String                   
city;

@Column(name = "STATE", length = 2, nullable = true) private String                    
state;

@Column(name = "ZIPCODE", length = 10, nullable = true) private String                
zipCode;

@Column(name = "COMPANYNAME", length = 25, nullable = true) private String            
companyName;

@OneToMany(fetch = FetchType.LAZY, mappedBy = "customer") private Set<ServiceRequest> 
requests;

public Customer()
{

}
...... getters/setters....

Client code:

byte[] getCustomerResponse = (byte[])    
RestClientUtil.sendGetMethod(urlGetCustomer + URLEncoder.encode(custNo, "UTF-8"));
Unmarshaller unmarshaller = RestClientUtil.getUnmarshaller(Customer.class);
StringReader reader = new StringReader(new String(getCustomerResponse));

Customer customer = (Customer) unmarshaller.unmarshal(reader);

I see the output as:

found customer :{"customer":{"city":"city1         ","companyName":"companyName1            ","custNo":"RCN1","email":"email1@ge.com","firstName":"first1                   ","gender":"F","lastName":"last1                    ","midInit":"K","phone":"4082229871      ","state":"CA","streetAddress":"streetAddress1","title":"S   ","zipCode":"zipCode   "}}

javax.xml.bind.UnmarshalException - with linked exception: [org.xml.sax.SAXParseException: Content is not allowed in prolog.] at javax.xml.bind.helpers.AbstractUnmarshallerImpl.createUnmarshalException(AbstractUnmarshallerImpl.java:315) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.createUnmarshalException(UnmarshallerImpl.java:526) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:223) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:137) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194) at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.getCustomerByCustNo(CustomerRemoteAgent.java:151) at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.execute(CustomerRemoteAgent.java:311) at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.main(CustomerRemoteAgent.java:368) Caused by: org.xml.sax.SAXParseException: Content is not allowed in prolog. at org.apache.xerces.util.ErrorHandlerWrapper.createSAXParseException(Unknown Source) at org.apache.xerces.util.ErrorHandlerWrapper.fatalError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLErrorReporter.reportError(Unknown Source) at org.apache.xerces.impl.XMLScanner.reportFatalError(Unknown Source) at org.apache.xerces.impl.XMLDocumentScannerImpl$PrologDispatcher.dispatch(Unknown Source) at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:217) ... 6 more java.lang.NullPointerException at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.submitRequest(CustomerRemoteAgent.java:167) at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.execute(CustomerRemoteAgent.java:313) at com.ge.dsp.iworkRemote.remoteAgents.CustomerRemoteAgent.main(CustomerRemoteAgent.java:368)


Solution

  • Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.

    The JAXB (JSR-222) specification does not cover JSON binding. When JAXB annotated models are used with JAX-RS implementations there is processing beyond the JAXB spec that is occuring. This is why when you try to use the standard JAXB APIs to process the JSON message you get an XML parser exception.

    Demo

    EclipseLink MOXy is a JAXB implementation that offers native support for JSON-binding (see: http://blog.bdoughan.com/2011/08/json-binding-with-eclipselink-moxy.html). Below is an example using your domain model as posted in your question (with accessors added)

    package forum13652303;
    
    import java.io.File;
    import java.util.*;
    import javax.xml.bind.*;
    import org.eclipse.persistence.jaxb.JAXBContextProperties;
    
    public class Demo {
    
        public static void main(String[] args) throws Exception {
            Map<String, Object> properties = new HashMap<String, Object>(1);
            properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
            JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);
    
            Unmarshaller unmarshaller = jc.createUnmarshaller();
            File json = new File("src/forum13652303/input.json");
            Customer customer = (Customer) unmarshaller.unmarshal(json);
    
            Marshaller marshaller = jc.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            marshaller.marshal(customer, System.out);
        }
    
    }
    

    jaxb.properties

    To use MOXy as your JAXB provider you need to add a file called jaxb.properties in the same package as your domain model with the following entry (see: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html):

    javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
    

    input.json/Output

    {
       "customer" : {
          "city" : "city1 ",
          "companyName" : "companyName1 ",
          "custNo" : "RCN1",
          "email" : "email1@ge.com",
          "firstName" : "first1 ",
          "gender" : "F",
          "lastName" : "last1 ",
          "midInit" : "K",
          "phone" : "4082229871 ",
          "state" : "CA",
          "streetAddress" : "streetAddress1",
          "title" : "S ",
          "zipCode" : "zipCode "
       }
    }