views:

1492

answers:

3

I'm working with eBay's LMS (Large Merchant Services) and kept running into the error:

org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.

After alot of trial and error I traced the problem down. It turns out this works:

<?xml version="1.0" encoding="UTF-8"?>
<BulkDataExchangeRequests xmlns="urn:ebay:apis:eBLBaseComponents">
  <Header>
    <Version>583</Version>
    <SiteID>0</SiteID>
  </Header>
  <AddFixedPriceItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">

while this (what I've been sending) doesn't:

<?xml version="1.0" encoding="UTF-8"?>
<BulkDataExchangeRequests xmlns="urn:ebay:apis:eBLBaseComponents">
  <Header>
    <Version>583</Version>
    <SiteID>0</SiteID>
  </Header>
  <AddFixedPriceItemRequest>

The difference is the xml namespace attribute on the AddFixedPriceItemRequest . All of my XML is currently being marshalled via JAXB and I'm not sure what is the best way to go about adding a second xmlns attribute to a different element in my file.

So that's the question. How do I add an xmlns attribute to another element in JAXB?

UPDATE:

package ebay.apis.eblbasecomponents;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "AddFixedPriceItemRequestType", propOrder = {
    "item"
})
public class AddFixedPriceItemRequestType
    extends AbstractRequestType
{

    @XmlElement(name = "Item")
    protected ItemType item;

    public ItemType getItem() {
        return item;
    }

    public void setItem(ItemType value) {
        this.item = value;
    }
}

Added class definition by request.

UPDATE 2: Edited the above class like so to no effect:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(namespace = "urn:ebay:apis:eBLBaseComponents",
name = "AddFixedPriceItemRequestType", propOrder = {
    "item"
})
public class AddFixedPriceItemRequestType

UPDATE 3: Here is a snippet of the BulkDataExchangeRequestsType class. I tried throwing a namespace="urn:ebay:apis:eBLBaseComponents" into the @XmlElement for AddFixedPriceItemRequest but it didn't do anything.

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BulkDataExchangeRequestsType", propOrder = {
    "header",
    "addFixedPriceItemRequest"
})
public class BulkDataExchangeRequestsType {

    @XmlElement(name = "Header")
    protected MerchantDataRequestHeaderType header;
    @XmlElement(name = "AddFixedPriceItemRequest")
    protected List<AddFixedPriceItemRequestType> addFixedPriceItemRequest;

UPDATE 4: Here's the hideous chunk of code that is updating the xml after marshalling for me. This is currently working although I'm not particulary proud of it.

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setNamespaceAware(true);
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.newDocument();
    marshaller.marshal(request, doc);
    NodeList nodes = doc.getChildNodes();
    nodes = nodes.item(0).getChildNodes();
    for(int i = 0; i < nodes.getLength(); i++){
        Node node = nodes.item(i);
        if (!node.getNodeName().equals("Header")){
            ((Element)node).setAttribute("xmlns", "urn:ebay:apis:eBLBaseComponents");
        }
    }

Thanks for all the help everyone.

+2  A: 

Try to use class annotation

@XmlType(namespace="urn:ebay:apis:eBLBaseComponents")

or

@XmlElement(namespace="urn:ebay:apis:eBLBaseComponents")

property annotation if you only want to specify namespace only in some certain cases

Mykola Golubyev
+1  A: 

As far as I can tell, your XML fragments are semantically identical. The xmlns attribute on the AddFixedPriceItemRequest element is redundant, since it implicitly inherits the namespace of its parent element. JAXB knows this, and so doesn't bother adding the namespace to AddFixedPriceItemRequest - it's just not necessary.

If the ebay server is only working when the AddFixedPriceItemRequest xmlns is present, then it's broken, and is making demands on the input over and above those required by XML and by the schema. If this is indeed the case (which is hard to believe, but possible), then using a Java XML document model like JAXB is going to be a struggle, since that will assume XML is XML is XML. Low-level farting about with which elements get the xmlns declarations is not exposed to the API, since it shouldn't be needed.

None of which is helping you. My approach would be to marshal the JAXB model to a DOM object (using a DOMResult passed to the Marshaller), and then see if you can do some manual tweaking of the DOM to force the xmlns into the document at the appropriate places. You can then serialize that DOM to XML and send that.

You shouldn't have to do this, and I suspect you may be doing something else wrong somewhere; this is more likely than the ebay web service being broken like this.


edit: here's another suggestion, a bit less awful than the JAXB-to-DOM-to-XML solution. If your request XML is reasonable static in structure, with only the numeric/string values changing, then define it as a String template, then replace the values at runtime, and send that. You can then interpret the results using JAXB. I've done this in the oast with web services thyat required very exact namespace prefixes, when persuading the java XML libraries to conform to that was unreasonably hard.

skaffman
You're right, it makes no sense at all, however, I've tested it - sending the exact same file (their LMS service requires you to upload a file that they then process when they get around to it basically) except for that one change of an extra xmlns. Without it, the service returns "Failed" every time. When it is there it doesn't have that problem. I guess I was hoping there was an easier way - dragging it through DOM seems really cumbersome but I'm getting the feeling any solution will be a beast at this point.
Ryan Elkins
see edit for an alternative
skaffman
Unfortunately that probably won't work as it is rather dynamic in how it creates its content. Good thought though is that wasn't the case.
Ryan Elkins
A: 

Even I am facing same issue, could anyone help me put

Anil