trf
trf

Reputation: 1394

How to unmarshal simple XML with single element and value

I'm try to unmarshal the following very simple XML received from an external web service using Spring's RestTemplate and JAXB:

<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://www.example.com/">0.061</double>

This is the class I'm using to unmarshal the XML. I've tried various combinations of @XmlRootElement, @XmlElement and @XmlValue, but can't get it to work.

@XmlRootElement
public class ExchangeRateWebServiceResponse {

    private double rate;

    @XmlElement(name = "double")
    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }    
}

The method which performs the web service call using RestTemplate:

public double getExchangeRate(String fromCurrency, String toCurrency, 
                              String exchangeRateURL) {
    RestTemplate restTemplate = new RestTemplate();

    ExchangeRateWebServiceResponse result = 
        restTemplate.getForObject(exchangeRateURL,
            ExchangeRateWebServiceResponse.class, 
                fromCurrency, toCurrency);

    return result.getRate();
}

This is the exception I am getting:

org.springframework.http.converter.HttpMessageNotReadableException: Could not unmarshal to [class za.co.example.server.finance.ExchangeRateWebServiceResponse]: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>
at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:82)
at org.springframework.http.converter.xml.AbstractXmlHttpMessageConverter.readInternal(AbstractXmlHttpMessageConverter.java:61)
at org.springframework.http.converter.AbstractHttpMessageConverter.read(AbstractHttpMessageConverter.java:153)
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:103)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:496)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:452)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:222)
at za.co.example.server.finance.ExchangeRateWebService.getExchangeRate(ExchangeRateWebService.java:21)
at za.co.example.test.suites.integration.component.external.ExchangeRateWebserviceTests.testGetZARToGBPRate_shouldReturnAnExchangeRate(ExchangeRateWebserviceTests.java:18)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:77)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.example.com/", local:"double"). Expected elements are <{}exchangeRateWebServiceResponse>
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:647)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:243)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:238)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:105)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1048)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:483)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:465)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:135)
at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source)
at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source)
at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.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.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:203)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:175)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:125)
at org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter.readFromSource(Jaxb2RootElementHttpMessageConverter.java:74)
... 34 more

Upvotes: 1

Views: 8150

Answers (2)

pappu_kutty
pappu_kutty

Reputation: 2488

you need to have namespace at your java object.

@XmlElement(name = "double", namespace = "http://www.example.com/" )

EDIT

you can config your namespace in separate package-info class and place it in you java class package

@XmlSchema(
xmlns = { namespace = "http://www.example.com/",
elementFormDefault = XmlNsForm.QUALIFIED) 

so that you can have namespace defined only at root level, no need to defined at every xml element, you can also have multiple namespace configured.

this link will give more details about package-info.java

http://java.dzone.com/articles/jaxb-and-root-elements

Upvotes: 3

trf
trf

Reputation: 1394

With the help of @pappu_kutty, I worked out that I needed to specify the namespace and element name in @XmlRootElement, and then add @XmlValue to either getRate() or setRate() to get the value of the root element.

@XmlRootElement(name = "double", namespace = "http://www.example.com/")
public class ExchangeRateWebServiceResponse {

    private double rate;

    @XmlValue
    public double getRate() {
        return rate;
    }

    public void setRate(double rate) {
        this.rate = rate;
    }

}

Upvotes: 1

Related Questions