JAXB : Unmarshal object with 2 name spaces results in a null value - java

I am getting null value when i try to unmarshal XML file ,
I have created package-info.java class with 2 name spaces as explained below.
Please suggest how to fix this issue
1. My XML file looks like below :It has 2 name spaces
<?xml version="1.0" encoding="UTF-8"?>
<saleResponse xmlns="http://tripos.vantiv.com/2014/09/TriPos.Api" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<_type>saleResponse</_type>
</saleResponse>
2. i have declared package-info.java like below
#XmlSchema(
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix="", namespaceURI="http://tripos.vantiv.com/2014/09/TriPos.Api"),
#XmlNs(prefix="i", namespaceURI="http://www.w3.org/2001/XMLSchema-instance")
}
)
#XmlAccessorType(XmlAccessType.FIELD)
package test1;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.*;
3. SaleResponse class is :
package test1;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "saleResponse", namespace = "http://tripos.vantiv.com/2014/09/TriPos.Api")
public class SaleResponse {
#XmlElement(name = "_type")
public String _type;
}
4. I am getting null value when i try to unmarshal XML file
package test1;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class JAXBExample {
public static void main(String[] args) {
try {
File file = new File("C:\\Ravi\\file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(SaleResponse.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
SaleResponse saleResponse = (SaleResponse) jaxbUnmarshaller.unmarshal(file);
System.out.println(saleResponse._type);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
**I am getting null value when i try to unmarshal XML file ,
I have created package-info.java class with 2 name spaces as explained below.
Please suggest how to fix this issue**

You have to add the default namespace="http://tripos.vantiv.com/2014/09/TriPos.Api" attribute into your package-info.java and you can remove the empty prefix one also: #XmlNs(prefix="", namespaceURI="http://tripos.vantiv.com/2014/09/TriPos.Api").
It should work as your expected, output is: saleResponse
package-info.java
#XmlSchema(elementFormDefault = XmlNsForm.QUALIFIED, namespace="http://tripos.vantiv.com/2014/09/TriPos.Api", xmlns = {
#XmlNs(prefix = "i", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance") })
#XmlAccessorType(XmlAccessType.FIELD)
package test1;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
import javax.xml.bind.annotation.*;
For more information: https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/XmlSchema.html

Related

How to change the xml properties from default properties?

The above screen capture shows the expected output and actual output, red color indicates that it differs from the actual output that is shown in green color.
To create xml document I have used the marshall concept.Java code used to create xml document are given below.
import com.ehf.bean.Invoice;
import com.sap._0050089212_one_off.ypt74nkey_.StandardFaultMessage;
import java.io.FileOutputStream;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.xml.sax.SAXException;
public class Ehf {
public static void main(String[] args) throws ParserConfigurationException,
TransformerException, SAXException, IOException, StandardFaultMessage,
com.sap.xi.a1s.global.StandardFaultMessage, JAXBException {
JAXBContext contextObj = JAXBContext.newInstance(Invoice.class);
Marshaller marshallerObj = contextObj.createMarshaller();
marshallerObj.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Invoice invoice = new Invoice();
invoice.setCustomizationID("dsf");
invoice.setInvoiceTypeCode(0);
marshallerObj.marshal(invoice, new FileOutputStream("question.xml"));
}
}
Note: Invoice class is generated using xsd, through xjc command.
How can resolve this problem?
#javax.xml.bind.annotation.XmlSchema(
namespace = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns ={#XmlNs(prefix="cac", namespaceURI="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"),
#XmlNs(prefix="cbc", namespaceURI="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"),
#XmlNs(prefix="", namespaceURI="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2")
})
The above code is working for me as expected, this code should be write in package-info.java

Maintain whitespace in JAXB with xs:any and mixed content

I have a schema with an xs:any element. This element may contain other elements that have mixed content. I'm trying to use JAXB to unmarshall it into Java objects (with the 'any' as an Element).
From the schema:
<xs:element name="a">
<xs:complexType>
<xs:sequence>
<xs:any processContents="lax"/>
</xs:sequence>
</xs:complexType>
</xs:element>
In general, this works. But when handling elements with mixed content, whitespace between nested nodes is lost.
test.xml:
<a><foo><b>Hello</b> <i>World</i></foo></a>
Unmarshalling like this:
JAXBContext jc = JAXBContext.newInstance(A.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream inputStream = this.getClass().getResourceAsStream("/data/test.xml");
A a = (A) unmarshaller.unmarshal(inputStream);
Marshaller marshaller = jc.createMarshaller();
marshaller.marshal(a, System.out);
Results in this:
<a><foo><b>Hello</b><i>World</i></foo></a>
I lose the space between the child tags of the <foo> element. I'm certain that it's the unmarshal step that takes the whitespace out here, but I do need it to survive the round trip.
Note that it's only whitespace-only text content that's removed. This works as desired:
<a><foo><b>Hello</b> to you <i>World</i></foo></a>
I tried adding xml:space="preserve" (see, for example, JAXB: How to keep consecutive spaces as they are in source XML during unmarshalling), but that has no effect on whitespace between elements. I've tried with processContents set to each of strict, lax, and skip, none of which helped.
After facing a similar issue I could come up with the following solution (to this specific scenario, as for some other complex XML structures it doesn't work perfectly).
package com.stackoverflow.answers;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlMixed;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.transform.stream.StreamSource;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.w3c.dom.Element;
public class XmlAnyElementWithWhiteSpacesTest {
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "a")
private static class A {
#XmlAnyElement
#XmlMixed
private List<Element> elements;
}
private static final String SAMPLE = "<a><foo><b>Hello</b> <i>World</i></foo></a>";
#Test
public void shouldParseAndSerializeKeepingWhiteSpaceElements() throws JAXBException {
// given
JAXBContext jc = JAXBContext.newInstance(A.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
InputStream inputStream = new ByteArrayInputStream(SAMPLE.getBytes(StandardCharsets.UTF_8));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
// when
JAXBElement<A> a = unmarshaller.unmarshal(new StreamSource(inputStream), A.class);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
marshaller.marshal(a.getValue(), outputStream);
String actual = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
// then
assertEquals(SAMPLE, actual);
}
}
The key points here are:
Usage of #XmlMixed annotation
Usage of StreamSource
You can use either List<Object> or List<Element> for your "XML any content" property.

Line number of xinclude while unmarshalling using jaxb

I found this question on SO. I shows how to get the line numbers of individual xml elements while unmarshalling with JAXB. I extended this example being able to use xinclude. Unfortunately, I'm not able to get the line number of the xinclude.
So, how do I get the line number of the actual xinclude statement? Here is the extended example:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.sax.SAXSource;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
public class Demo {
public static void main(String[] args) throws JAXBException, SAXException,
ParserConfigurationException, FileNotFoundException {
JAXBContext jc = JAXBContext.newInstance(Person.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
SAXParserFactory spf = SAXParserFactory.newInstance();
spf.setXIncludeAware(true);
spf.setNamespaceAware(true);
spf.setValidating(true);
File file = new File("src/person.xml");
XMLReader xr = spf.newSAXParser().getXMLReader();
xr.setEntityResolver(new EntityResolver() {
#Override
public InputSource resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
System.out.println(publicId + " -> " + systemId);
return null;
}
});
SAXSource source = new SAXSource(xr, new InputSource(
new FileInputStream(file)));
Person person = (Person) unmarshaller.unmarshal(source);
System.out.println("Person: " + person.locator.getLineNumber());
System.out.println("Address: "
+ person.address.locator.getLineNumber());
}
}
The EntityResolver listener tells me that there is an xinclude statement, but I don't know on which line number.
person.xml
<?xml version="1.0" encoding="UTF-8"?>
<person xmlns:xi="http://www.w3.org/2001/XInclude">
<name>Jane Doe</name>
<xi:include href="./src/address.xml" />
</person>
address.xml
<?xml version="1.0" encoding="UTF-8"?>
<address>1 A Street</address>
I didn't mention the Person and Address class, so this questions stays short and compact :) I also marked every Locator field with #XmlTransient. Thank you!

calling Restful Service from Java

Here I am not creating a RESTful service indeed I have to call an external Restful service from my java code. Currently I am implementing this using Apache HttpClient.
The response that I get from the web service is in XML format.
I need to extract the data from XML and put them on Java objects.
Rather than using SAX parser, I heard that we can use JAX-RS and JERSEY which automatically maps the xml tags to corresponding java objects.
I have being looking through but unable to find a source to get started.
I did look at existing links
Consuming RESTful APIs using Java
RESTful call in Java
Any help is appreciated in moving forward.
Thanks!!
UPDATE
as follow up with this: Can I do this way?? if the xml being returned
as 4
.....
If I am constructing a Person object, I believe this will choke up.
Can I just bind only the xml elements that I want? if Yes how can I do
that.
You could map this XML as follows:
input.xml
<?xml version="1.0" encoding="UTF-8"?>
<Persons>
<NumberOfPersons>2</NumberOfPersons>
<Person>
<Name>Jane</Name>
<Age>40</Age>
</Person>
<Person>
<Name>John</Name>
<Age>50</Age>
</Person>
</Persons>
Persons
package forum7177628;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="Persons")
#XmlAccessorType(XmlAccessType.FIELD)
public class Persons {
#XmlElement(name="Person")
private List<Person> people;
}
Person
package forum7177628;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
#XmlElement(name="Name")
private String name;
#XmlElement(name="Age")
private int age;
}
Demo
package forum7177628;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Persons.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Persons persons = (Persons) unmarshaller.unmarshal(new File("src/forum7177628/input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(persons, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Persons>
<Person>
<Name>Jane</Name>
<Age>40</Age>
</Person>
<Person>
<Name>John</Name>
<Age>50</Age>
</Person>
</Persons>
ORIGINAL ANSWER
Below is an example of calling a RESTful service using the Java SE APIs including JAXB:
String uri =
"http://localhost:8080/CustomerService/rest/customers/1";
URL url = new URL(uri);
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Accept", "application/xml");
JAXBContext jc = JAXBContext.newInstance(Customer.class);
InputStream xml = connection.getInputStream();
Customer customer =
(Customer) jc.createUnmarshaller().unmarshal(xml);
connection.disconnect();
For More Information:
http://blog.bdoughan.com/2010/08/creating-restful-web-service-part-55.html
JAX-RS is the Java api for restful webservice. Jersey is an implementation from sun/oracle.
You need jaxb to convert your xml to a POJO. But it is not the always case that, converted object can be used without any transformation. If this is the scenario SAXParser is a nice solution.
Here is a nice tutorial on JAXB.
You could consider using jaxb to bind your java objects to an xml document (marshalling).
http://www.oracle.com/technetwork/articles/javase/index-140168.html#xmp1
I use Apache CXF to build my RESTful services, which is another JAX-RS implementation (it also provides a JAX-WS implementation). I also use its "org.apache.cxf.jaxrs.client.WebClient" class in unit tests, which will completely manage all the marshalling and unmarshalling under the covers. You give it a URL and ask for an object of a particular type, and it does all the work. I don't know if Jersey has similar facilities.
If you also need to convert that xml string that comes as a response to the service call, an x object you need can do it as follows:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXB;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class RestServiceClient {
// http://localhost:8080/RESTfulExample/json/product/get
public static void main(String[] args) throws ParserConfigurationException,
SAXException {
try {
URL url = new URL(
"http://localhost:8080/CustomerDB/webresources/co.com.mazf.ciudad");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/xml");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP error code : "
+ conn.getResponseCode());
}
BufferedReader br = new BufferedReader(new InputStreamReader(
(conn.getInputStream())));
String output;
Ciudades ciudades = new Ciudades();
System.out.println("Output from Server .... \n");
while ((output = br.readLine()) != null) {
System.out.println("12132312");
System.err.println(output);
DocumentBuilder db = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(output));
Document doc = db.parse(is);
NodeList nodes = ((org.w3c.dom.Document) doc)
.getElementsByTagName("ciudad");
for (int i = 0; i < nodes.getLength(); i++) {
Ciudad ciudad = new Ciudad();
Element element = (Element) nodes.item(i);
NodeList name = element.getElementsByTagName("idCiudad");
Element element2 = (Element) name.item(0);
ciudad.setIdCiudad(Integer
.valueOf(getCharacterDataFromElement(element2)));
NodeList title = element.getElementsByTagName("nomCiudad");
element2 = (Element) title.item(0);
ciudad.setNombre(getCharacterDataFromElement(element2));
ciudades.getPartnerAccount().add(ciudad);
}
}
for (Ciudad ciudad1 : ciudades.getPartnerAccount()) {
System.out.println(ciudad1.getIdCiudad());
System.out.println(ciudad1.getNombre());
}
conn.disconnect();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
public static String getCharacterDataFromElement(Element e) {
Node child = e.getFirstChild();
if (child instanceof CharacterData) {
CharacterData cd = (CharacterData) child;
return cd.getData();
}
return "";
}
}
Note that the xml structure that I expected in the example was as follows:
<ciudad><idCiudad>1</idCiudad><nomCiudad>BOGOTA</nomCiudad></ciudad>

Parsing XML document YQL query in Java

I want to use the information from XML response produced by using YQL for stock historical data, like this link
http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.historicaldata%20where%20symbol%20in%20(%22MSFT%22)%20and%20startDate%3D%222011-2-12%22%20and%20endDate%3D%222011-2-15%22%0A%09%09&diagnostics=true&env=http%3A%2F%2Fdatatables.org%2Falltables.env
And store it into a stock objects array. I am new to Java and I have no knowledge of its XML api's. I dont know what is the simple way to do it. Can someone suggest me a good solution. Thanks.
You could do the following using a JAXB (JSR-222) implementation:
Metro JAXB (the reference implementation included in Java SE 6)
EclipseLink JAXB (MOXy), I'm the tech lead
Apache JaxMe
etc.
Demo
import java.io.InputStream;
import java.net.URL;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Stock.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
URL url = new URL("http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.historicaldata%20where%20symbol%20in%20(%22MSFT%22)%20and%20startDate%3D%222011-2-12%22%20and%20endDate%3D%222011-2-15%22%0A%09%09&diagnostics=true&env=http%3A%2F%2Fdatatables.org%2Falltables.env");
InputStream xmlStream = url.openStream();
Stock stock = (Stock) unmarshaller.unmarshal(xmlStream);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(stock, System.out);
}
}
Stock
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="query")
#XmlAccessorType(XmlAccessType.FIELD)
public class Stock {
#XmlElementWrapper(name="results")
#XmlElement(name="quote")
private List<Quote> quotes;
}
Quote
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
#XmlAccessorType(XmlAccessType.FIELD)
public class Quote {
#XmlElement(name="Date")
#XmlSchemaType(name="date")
private Date date;
#XmlElement(name="Open")
private double open;
#XmlElement(name="High")
private double high;
#XmlElement(name="Low")
private double low;
#XmlElement(name="Close")
private double close;
#XmlElement(name="Volume")
private long volume;
#XmlElement(name="Adj_Close")
private double adjClose;
}

Categories