What should be the jaxb annotations for this xml file? - java

I have a xml file payload which i want to unmarshal using jaxb, I've created a pojo class for unmarshalling and I've defined xml attributes and elements to that pojo, but i'm a little bit confused about namespaces, how to annotate them?
My xml file:
<ns1:ContractLinkEvent xmlns:ns0="http://Enterprise.BizTalk.Canonical.Schemas/v2.0/ESB" xmlns:ns1="http://Enterprise.BizTalk.MCF.Core.Schemas/v2.0/ESB">
<Header xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
</Header>
<ContractLink xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ContractLinkId>1509148</ContractLinkId>
<BillingProfile>
<BillingProfileId>173886</BillingProfileId>
<BillingProfileCode xsi:nil="true"/>
</BillingProfile>
</ContractLink>
</ns1:ContractLinkEvent>
My Jaxb annotated Pojo is:
#XmlRootElement(name = "ContractLinkEvent", namespace="http://Enterprise.BizTalk.Canonical.Schemas/v2.0/ESB")
#XmlAccessorType(XmlAccessType.FIELD)
public class ContractLinkPojo {
#XmlElement(name="Header")
private String Header;
#XmlElement(name="ContractLink")
private String ContractLink;
.
.
.
goes on
I'm getting the following exception while unmarshalling:
java.io.IOException: javax.xml.bind.UnmarshalException
- with linked exception:
[com.sun.istack.SAXParseException2; lineNumber: 1; columnNumber: 1; unexpected element (uri:"http://Enterprise.BizTalk.MCF.Core.Schemas/v2.0/ESB", local:"ContractLinkEvent"). Expected elements are (none)]
I don't think i've defined the namespaces correctly because i haven't yet defined namespaces as i' still confused, any ideas?
EDIT:
This is my routing for unmarshalling
rest("/readXml")
.consumes("application/xml")
.post()
.to("direct:xmlread");
from("direct:xmlread").streamCaching()
.doTry().unmarshal(xmlDataFormat)
.process(readAndInsertXml)
.to("mock:result").end();
}

Namespaces are similar to package names in Java. You use that to have an unique name for XML elements you create so that they do not conflict with other XML elements.
You can define a default XML namespace as:
xmlns="http://Enterprise.BizTalk.Canonical.Schemas/v2.0/ESB"
You can define multiple XML namespace with prefixes as:
xmlns:ns0="..."
xmlns:ns1="..."
In the above ns0 and ns1 are prefixes you created.
In your xml, you have not defined any default namespace. So, I guess you are trying to use namespace prefixes ns0 and ns1 to identity elements. In such a case, you have used ns1 for ContractLinkElement but not < Header >, < ContractLink > or anything else. However, ns0 is not used anywhere and if not required, you can remove that. Please check if this is what you intended to do.
Also, there is no ending tag:
<ns1:ContractLinkEvent
xmlns:ns0="http://Enterprise.BizTalk.Canonical.Schemas/v2.0/ESB"
xmlns:ns1="http://Enterprise.BizTalk.MCF.Core.Schemas/v2.0/ESB">

Related

JAXB - how to detect duplicate nodes while unmarshalling

Is it possible to report duplicate nodes while unmarshalling XML without validating it against XML schema? Suppose XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<user xmlns=...>
<firstName>Peter</firstName>
<lastName>Smith</lastName>
<firstName>Eric</firstName>
</user>
and here's the java class (annotations omitted):
public class User {
protected String firstName;
protected String lastName;
.... [getters and setters here]
}
The above XML gets successfully unmarshalled into a User object with firstName=Eric and lastName=Smith. Instead, I want it to fail and report the presence of duplicate element firstName.
We don't use validation against XSD because we support both XML and JSON, so chose to use Bean Validation against annotations contained in JAXB beans (generated java classes). Which works pretty well, but obviously cannot take care of the described problem.

How to remove namespace prefix from XML response using XSD?

I have generated Java classes from an XSD, and in my XML responses I am getting a ns2: prefix which I do not need.
For example, I am getting this response:
<ns2:location xmlns:ns2="http://www.example.com/">
<ns2:response/>
</ns2:location>
But the response I am expecting is as follows:
<location>
<response/>
</location>
Your example shows not just a namespace prefix (ns2) declaration but also an actual namespace (http://www.example.com/ for the location and response elements) as not being desired.
If you have full control over the XSD, you can remove the
targetNamespace="http://www.example.com/"
attribute from the xs:schema element in the XSD. Elements of XML documents conforming to this XSD will then no longer be in any namespace, and your generated Java classes will reflect this new setting.
However, be aware that deleting (or changing) targetNamespace effectively changes the names of the components defined in the XSD. Think twice about making such a change if the XSD is defined by another party or otherwise already in use by others.

how to unmarshall an XML String with Name space to Java Object

hi I got the following response as a string when hitting a client.
I need to unmarshall it so that I can set the values in a Java object and send it back to front end. Kindly help me to convert the following xml string to jaxb object.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:ValidateAustralianAddressResponse xmlns:ns2="http://api.auspost.com.au/ValidateAustralianAddress:v1">
<Address><AddressLine>481 CHURCH ST</AddressLine><SuburbOrPlaceOrLocality>RICHMOND</SuburbOrPlaceOrLocality><StateOrTerritory>VIC</StateOrTerritory><PostCode>3121</PostCode><DeliveryPointIdentifier>55461002</DeliveryPointIdentifier><Country><CountryCode>AU</CountryCode><CountryName>Australia</CountryName></Country></Address>
<ValidAustralianAddress>true</ValidAustralianAddress>
</ns2:ValidateAustralianAddressResponse>
Metadata
Since only the root element is namespace qualified you just need to set the namespace parameter on the #XmlRootElement annotation.
#XmlRootElement(name="ValidateAustralianAddressResponse", namespace="http://api.auspost.com.au/ValidateAustralianAddress:v1")
public class ValidateAustralianAddressResponse {
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
Converting XML to Object
You can wrap the XML String in an instance of StringReader and unmarshal that.
For More Information
http://blog.bdoughan.com/2011/08/jaxb-and-java-io-files-streams-readers.html

Spring web service returning different results when using JAXB or XML DOM objects

I have a JAXB object (ProductRequest) that represents an XML document for a webservice request. Assume it looks something like this:
<ProductRequest>
<getProducts/>
</ProductRequests>
For the response, the JAXB object (ProductResponse) will represent an XML document as shown below:
<ProductResponse>
<productId>1</productId>
<productName>Oranges</productName>
<productId>2</productId>
<productName>Apples</productName>
</ProductResponse>
Using Spring-WS, i can send the web service the request using two approaches
Using the JAXB object
ProductRequest productRequest = new productRequest();
ProductResponse productResponse = (ProductResponse) webServiceTemplate
.marshalSendAndReceive(productRequest);
Using plain XML/DOM
DOMResult domresult = new DOMResult();
webServiceTemplate.sendSourceAndReceiveToResult(source, domresult); //source represents the XML document as a DOMSource object
Element responseElement = (Element) domresult.getNode().getFirstChild();
When i try both approaches, the results are different. The first approach using the JAXB object the result is
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProductResponse xmlns="http://mySchema">
<productId>1</productId>
<productName>Oranges</productName>
<productId>2</productId>
<productName>Apples</productName>
</ProductResponse>
The second approach using the XML Dom object the result is (Includes namespaces)
<?xml version="1.0" encoding="UTF-8"?>
<ns2:ProductResponse xmlns:ns2="http://mySchema">
<ns2:productId>1</ns2:productId>
<ns2:productName>Oranges</ns2:productName>
<ns2:productId>2</ns2:productId>
<ns2:productName>Apples</ns2:productName>
</ns2:ProductResponse>
The header for the schema used for the response on the web service is declared as:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:z="http://mySchema"
targetNamespace="http://mySchema"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
-- Schema elements
</xs:schema>
There are two differences in the response
The first line on the response from JAXB request includes the entry standalone="yes">
The elements on the JAXB version are not prefixed with the namespace
Shouldn't the response with elements prefixed with the schema have used "z" (as defined in the schema) instead of ns2?
I don't understand what could be causing this difference given that they are both calling the same web service which generates the response based on the same schema. Any ideas?
The XML content is the same but the difference in the format of the XML is giving me problems as i cant use String.equals() to compare the two.
The responses are the same, just that one isn't qualified with a namespace.
On a side note, your XML design looks a bit flaky. Might be better like this;
<ProductResponse>
<product>
<id>1</id>
<name>Oranges</name>
</product>
<product>
<id>2</id>
<name>Apples</name>
</product>
</ProductResponse>
Why? Because you shouldn't rely on the order of elements.
The result is the same. ns2 is just the prefix for the namespace, jaxb uses default namespace and XML Dom uses a the prefix ns2. The xml files are equivalent, and both of them are valid against that schema. You can read more about XML namespace here.

Add Xml namespace using Jaxb

I am creating amazon feed, the feed xml should be like:
<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">
I am using jaxb to generate xml files from java classes, I used NamespacePrefixMapperImpl from jaxb samples to add namespaces to the xml. But currently it generates the root like:
<AmazonEnvelope xmlns:xsi:noNamespaceSchemaLocation="amzn-envelope.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
how I can remove the xmlns from amzn-envelope.xsd??
Here's the mapping I used in NamespacePrefixMapperImpl
if( "http://www.w3.org/2001/XMLSchema-instance".equals(namespaceUri) )
return "xsi";
if("amzn-envelope.xsd".equals(namespaceUri))
return "xsi:noNamespaceSchemaLocation";
I found a property at Marshaller that can add the amzn-envelope.xsd:
marshaller.setProperty("jaxb.noNamespaceSchemaLocation", "amzn-envelope.xsd");
and left the NamespacePrefixMapper to add the "http://www.w3.org/2001/XMLSchema-instance".
Hope this helps others.
If I understand your intent, your document has a default namespace, and you're trying to add the schemalLocation for that namespace.
NamespacePrefixMapper won't let you do this, it's useful only for picking a prefix for a namespace. There are no namespaces in this document, and so no useful way of using NamespacePrefixMapper. It can't be used for adding schemaLocation hints - those are treated specially by JAXB, and you're just confusing it.
Are you sure you need the noNamespaceSchemaLocation="amzn-envelope.xsd" at all? Have you tried sending it to the web service without it?

Categories

Resources