Exception in thread “main” javax.xml.bind.Unmarsha

2019-09-14 18:13发布

问题:

I am a .NET Developer learning Java. Please see the code below:

The class HelloWorld

import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
import javax.ws.rs.core.MediaType;

@Path("generic")
public class HelloWorld {
    @Context
    private UriInfo context;
    public HelloWorld() {
    }
    @GET
    @Produces("application/xml")
    public String getHtml() {
        return "<?xml version='1.0'?><PARTS><TITLE>Computer Parts</TITLE><PART><ITEM>Motherboard</ITEM></PART></PARTS>";
    }
}

The class JavaApplication3

package javaapplication3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.stream.Collectors;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import sun.misc.IOUtils;

/**
 *
 * @author 3212627
 */
public class JavaApplication3 {
    private static String charset;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws MalformedURLException, IOException, JAXBException {
        //Get the URI by selecting the RESTful web services folder under the web app project.   Then right click on the underlying node
        //and select: TestResourceURI
        String content;
        String uri ="http://localhost:8080/HelloRestService/webresources/generic";
        URL url = new URL(uri);
        HttpURLConnection connection =  (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        //connection.setRequestProperty("Accept", "application/xml");
        connection.setRequestProperty("Accept", "application/xml");

        JAXBContext jc = JAXBContext.newInstance(String.class); //I changed Customer.class to String.class

        InputStream xml = connection.getInputStream();
        String str = (String) jc.createUnmarshaller().unmarshal(xml); //line causing exception
        connection.disconnect();       
    }

}

The exception returned is:

Exception in thread "main" javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"PARTS"). Expected elements are (none)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:380)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:619)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3129)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:880)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606)
    at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:118)
    at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:504)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848)
    at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777)
    at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
    at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
    at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243)
    at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
    at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:204)
    at javaapplication3.JavaApplication3.main(JavaApplication3.java:46)
Java Result: 1
BUILD SUCCESSFUL (total time: 5 seconds)

I have marked the line that causes the exception. What is the problem?

回答1:

The main purpose of JAXB is to do the mapping between XML and a Java Bean but to be able to do it, it relies on annotations from javax.xml.bind.annotation that you need to declare on the fields or on the getters of your target Java Bean.

So for example here, your mapping could be defined as next:

The class Parts

public class Parts {
    @XmlElement(name = "TITLE")
    private String title;
    @XmlElement(name = "PART")
    private List<Part> parts;

    public String getTitle() {
        return this.title;
    }

    public void setTitle(final String title) {
        this.title = title;
    }

    public List<Part> getParts() {
        return this.parts;
    }

    public void setParts(final List<Part> parts) {
        this.parts = parts;
    }
}

The class Part

@XmlAccessorType(XmlAccessType.FIELD)
public class Part {
    @XmlElement(name = "ITEM")
    private String item;

    public String getItem() {
        return this.item;
    }

    public void setItem(final String item) {
        this.item = item;
    }
}

Once you have your mapping defined, you need to provide it to your JAXBContext to be able to unmarshal your XML content to get an instance of the class Parts:

JAXBContext jc = JAXBContext.newInstance(Parts.class); 

InputStream xml = connection.getInputStream();
Parts parts = (Parts) jc.createUnmarshaller().unmarshal(xml); 

Here is a good tutorial about JAXB that you should read. You should also read the one from oracle.