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>
Related
I have some kind of complex XML data structure. The structure contains different fragments like in the following example:
<data>
<content-part-1>
<h1>Hello <strong>World</strong>. This is some text.</h1>
<h2>.....</h2>
</content-part1>
....
</data>
The h1 tag within the tag 'content-part-1' is of interest. I want to get the full content of the xml tag 'h1'.
In java I used the javax.xml.parsers.DocumentBuilder and tried something like this:
String my_content="<h1>Hello <strong>World</strong>. This is some text.</h1>";
// parse h1 tag..
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(new InputSource(new StringReader(my_content)));
Node node = doc.importNode(doc.getDocumentElement(), true);
if (node != null && node.getNodeName().equals("h1")) {
return node.getTextContent();
}
But the method 'getTextContent()' will return:
Hello World. This is some text.
The tag "strong" is removed by the xml parser (as it is the documented behavior).
My question is how I can extract the full content of a single XML Node within a org.w3c.dom.Document without any further parsing the node content?
Although java DOM parser provides functionality for parsing mixed content, in this particular case it could be more convenient to use Jsoup library. When using it code to extract h1 element content would be as follows:
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
String text = "<data>\n"
+ " <content-part1>\n"
+ " <h1>Hello <strong>World</strong>. This is some text.</h1>\n"
+ " <h2></h2>\n"
+ " </content-part1>\n"
+ "</data>";
Document doc = Jsoup.parse(text);
Elements h1Elements = doc.select("h1");
for (Element h1 : h1Elements) {
System.out.println(h1.html());
}
Output in this case will be "Hello <strong>World</strong>. This is some text."
What you probaly want is XML generation from some subnode of your document.
So with slighlty modified nodeToString from earlier answer to similar question I can propose to
generate text <h1>Hello <strong>World</strong>. This is some text.</h1>. Some extra effor might be needed to get rid of <h1> and </h1>
package com.github.vtitov.test;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringReader;
import java.io.StringWriter;
import static org.hamcrest.MatcherAssert.*;
import static org.hamcrest.Matchers.*;
public class XmlTest {
#Test
public void buildXml() throws Exception {
String my_content="<h1>Hello <strong>World</strong>. This is some text.</h1>";
// parse h1 tag..
DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = documentBuilder.parse(new InputSource(new StringReader(my_content)));
Node node = doc.importNode(doc.getDocumentElement(), true);
String h1Content = null;
if (node != null && node.getNodeName().equals("h1")) {
h1Content = nodeToString(node);
}
assertThat("h1", h1Content, equalTo("<h1>Hello <strong>World</strong>. This is some text.</h1>"));
}
private static String nodeToString(Node node) throws TransformerException {
StringWriter sw = new StringWriter();
Transformer t = TransformerFactory.newInstance().newTransformer();
t.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
t.setOutputProperty(OutputKeys.INDENT, "no");
t.transform(new DOMSource(node), new StreamResult(sw));
return sw.toString();
}
}
I am trying to convert a Pojo to XML using the JAXB library.
I need the end result to look something like this:
<soap:Envelope
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<!--other stuff-->
</soap:Body>
</soap:Envelope>
I have tried a few different ways but so far I have no success, here is my latest attempt.
#XmlRootElement(name = "soap:Envelope")
public class Envelope {
private SoapBody soapBody;
public String toString() {
return "ClassPojo [SoapBody = " + soapBody + "]";
}
public SoapBody getSoapBody() {
return soapBody;
}
#XmlElement(name = "soap:Body")
public void setSoapBody(SoapBody soapBody) {
this.soapBody = soapBody;
}
}
this converts to the following result (but it's missing the XMLNS lines):
<soap:Envelope>
<soap:Body>
<!--Other stuff-->
</soap:Body>
</soap:Envelope>
I have tried adding a namespace tag to the declaration:
#XmlRootElement(name = "soap:Envelope", namespace = "soap")
but it just made the line convert to this <ns2:soap:Envelope xmlns:ns2="soap">
Edit:
OutputStream os = connection.getOutputStream();
JAXBContext jaxbContext =
JAXBContext.newInstance(MyOtherStuffObject.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(myObject, os);
os.flush();
I have tried adding a namespace tag to the declaration:
#XmlRootElement(name = "soap:Envelope", namespace = "soap")
but it just made the line convert to this
you are in one step out of what you need...
soap namespace is http://schemas.xmlsoap.org/soap/envelope/ not soap so... what if it will be like that?
#XmlRootElement(name = "soap:Envelope", namespace = "http://schemas.xmlsoap.org/soap/envelope/")
BTW. but do you really need to create SOAP Envelope manually? actually standard package javax.xml.soap has everything to work with SOAP where you can wrap your "other stuff" into SOAP Envelope and do not care about building it by your-self?
UPDATED:
I strongly recommend to use normal frameworks when working with SOAP web services, like Apache CXF or such, instead of manipulating SOAP on that low level.
But it can be done with standard JDK classes.
Example code:
package com.foo.tests;
import java.io.ByteArrayOutputStream;
import java.util.Calendar;
import java.util.UUID;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPMessage;
import org.w3c.dom.Document;
public class TestSOAPMessage {
static MessageFactory factory;
static DocumentBuilderFactory documentFactory;
static JAXBContext jaxbCtx;
static com.foo.tests.pojo.ObjectFactory myStuffFactory = new com.foo.tests.pojo.ObjectFactory();
static {
try {
factory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
documentFactory = DocumentBuilderFactory.newInstance();
jaxbCtx = JAXBContext.newInstance(com.foo.tests.pojo.MyStuffPojo.class);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String... args) {
try {
// prepare test MyStuff JAXB POJO
com.foo.tests.pojo.MyStuffPojo myStuff = myStuffFactory.createMyStuffPojo();
// populate myStuff Pojo
myStuff.setMyPropertyA("property A");
myStuff.setTimestamp(Calendar.getInstance());
myStuff.setMessageId(UUID.randomUUID().toString());
//---
// marshal JAXB Pojo to DOM Document
Document myStuffDoc = documentFactory.newDocumentBuilder().newDocument();
//*** myStuff has #XmlRootElement annotation
jaxbCtx.createMarshaller().marshal(myStuff, myStuffDoc);
//*** myStuff does not have #XmlRootElement annotation wrap it and use JAXBElement instead
// JAXBElement<com.foo.tests.pojo.MyStuffPojo myStuff> jaxbWrapper = myStuffFactory.createMyStuffPojo(myStuff);
// jaxbCtx.createMarshaller().marshal(jaxbWrapper, myStuffDoc);
//marshal JAXB Pojo to DOM Document
Document myStuffDoc = documentFactory.newDocumentBuilder().newDocument();
jaxbCtx.createMarshaller().marshal(jaxbWrapper, myStuffDoc);
//Create SOAPMessage
SOAPMessage myMessage = factory.createMessage();
//Optional if we'd like to set those properties...
myMessage.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
myMessage.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "utf-8");
// set myStuff into SOAPBody
myMessage.getSOAPBody().addDocument(myStuffDoc);
//All done. Save changes
myMessage.saveChanges();
// Just for test: print message
ByteArrayOutputStream finalBos = new ByteArrayOutputStream();
myMessage.writeTo(finalBos);
System.out.println("my Message: \r\n" + new String(finalBos.toByteArray()));
} catch (Exception e) {
e.printStackTrace();
}
}
}
What about adding the namespace attribute in your java bean? or
JAXB also provides the #XMLSchema annotation, which we can use to generate namespace.
You can do as below.
#javax.xml.bind.annotation.XmlSchema(namespace="http://www.springframework.org/schema/beans" , elementFormDefault=javax.xml.bind.annotation.XmlNsForm.QUALIFIED,
xmlns={ #javax.xml.bind.annotation.XmlNs(namespaceURI="http://www.w3.org/2001/XMLSchema-instance", prefix="xsi"),
#javax.xml.bind.annotation.XmlNs(namespaceURI="http://schemas.xmlsoap.org/soap/envelope/", prefix="soap")
}
)
Have also a look on this
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!
This question already has answers here:
How do you create a REST client for Java? [closed]
(18 answers)
Closed 2 years ago.
Using Java tools,
wscompile for RPC
wsimport for Document
etc..
I can use WSDL to generate the stub and Classes required to hit the SOAP Web Service.
But I have no idea how I can do the same in REST.
How can I get the Java classes required for hitting the REST Web Service.
What is the way to hit the service anyway?
Can anyone show me the way?
Working example, try this:
package restclient;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
public class NetClientGet {
public static void main(String[] args) {
try {
URL url = new URL("http://localhost:3002/RestWebserviceDemo/rest/json/product/dynamicData?size=5");//your url i.e fetch data from .
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept", "application/json");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("Failed : HTTP Error code : "
+ conn.getResponseCode());
}
InputStreamReader in = new InputStreamReader(conn.getInputStream());
BufferedReader br = new BufferedReader(in);
String output;
while ((output = br.readLine()) != null) {
System.out.println(output);
}
conn.disconnect();
} catch (Exception e) {
System.out.println("Exception in NetClientGet:- " + e);
}
}
}
As others have said, you can do it using the lower level HTTP API, or you can use the higher level JAXRS APIs to consume a service as JSON. For example:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://host:8080/context/rest/method");
JsonArray response = target.request(MediaType.APPLICATION_JSON).get(JsonArray.class);
Its just a 2 line of code.
import org.springframework.web.client.RestTemplate;
RestTemplate restTemplate = new RestTemplate();
YourBean obj = restTemplate.getForObject("http://gturnquist-quoters.cfapps.io/api/random", YourBean.class);
Ref. Spring.io consuming-rest
The code below will help to consume rest api via Java.
URL - end point rest
If you dont need any authentication you dont need to write the authStringEnd variable
The method will return a JsonObject with your response
public JSONObject getAllTypes() throws JSONException, IOException {
String url = "/api/atlas/types";
String authString = name + ":" + password;
String authStringEnc = new BASE64Encoder().encode(authString.getBytes());
javax.ws.rs.client.Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target(host + url);
Invocation.Builder invocationBuilder = webTarget.request(MediaType.APPLICATION_JSON).header("Authorization", "Basic " + authStringEnc);
Response response = invocationBuilder.get();
String output = response.readEntity(String.class
);
System.out.println(response.toString());
JSONObject obj = new JSONObject(output);
return obj;
}
Just make an http request to the required URL with correct query string, or request body.
For example you could use java.net.HttpURLConnection and then consume via connection.getInputStream(), and then covnert to your objects.
In spring there is a restTemplate that makes it all a bit easier.
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>
Look at Jersey. Again, REST is all about the data. And a tutorial here
JAX-RS but you can also use regular DOM that comes with standard Java
From your question its not clear whether you are using any frameworks.For REST you will be getting an WADL & Apache CXF recently added support for WADL-first development of REST services.Please go through http://cxf.apache.org/docs/index.html
You can able to consume a Restful Web service in Spring using RestTemplate.class.
Example :
public class Application {
public static void main(String args[]) {
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> call= restTemplate.getForEntity("http://localhost:8080/SpringExample/hello",String.class);
System.out.println(call.getBody())
}
}
Reference
Apache Http Client APIs are very commonly used for calling HTTP Rest services.
Here is one of example of consuming HTTP GET call.
import java.io.IOException;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.HttpClientBuilder;
public class CallHTTPGetService {
public static void main(String[] args) throws ClientProtocolException, IOException {
HttpClient client = HttpClientBuilder.create().build();
HttpUriRequest httpUriRequest = new HttpGet("URL");
HttpResponse response = client.execute(httpUriRequest);
System.out.println(response);
}
}
Use following maven dependency if using Maven project.
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpmime -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.5.1</version>
</dependency>
I have some classes that already use DOM4J to read XML files and provide
getter methods to the data. Now, I need to add the possibility of checking XML digital
signatures.
Using org.w3c.dom and following http://java.sun.com/developer/technicalArticles/xml/dig_signature_api/
everything works correctly.
So, I try to use DOMWriter to convert from org.dom4j.Document to
org.w3c.dom.Document, but after this the signature validation doesn't work. I think it
happens because DOMWiter is changing the XML tree (as doc4.asXML() seems to show).
I try to find something to set in order to mantain the integrity of the document, but
DOMWriter don't have such methods.
Below is the code demonstrating the asymmetric conversion.
The file used for tests is http://www.robertodiasduarte.com.br/files/nfe/131090007910044_v1.10-procNFe.xml
Does someone know reasons/workarounds to this?
Thanks (and sorry my poor english).
package testevalidanfe;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import javax.swing.JOptionPane;
import javax.xml.crypto.dsig.XMLSignature;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.dom4j.io.XMLWriter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
public class Testevalidanfe {
public static void main(String[] args) throws Exception {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
DocumentBuilder db = dbf.newDocumentBuilder();
Document d = db.parse("exemplo-nfe.xml");
Node no = d.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
DOMValidateContext valContext = new DOMValidateContext(new X509KeySelector(), no);
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
JOptionPane.showMessageDialog(null, "Validation using org.w3c.dom: " + signature.validate(valContext));
org.dom4j.io.DOMReader domreader = new org.dom4j.io.DOMReader();
org.dom4j.Document doc4 = domreader.read(d);
org.dom4j.io.DOMWriter domwriter = new org.dom4j.io.DOMWriter();
d = domwriter.write(doc4);
String after = doc4.asXML();
PrintWriter writer = new PrintWriter(new File("after-convertion.xml"));
writer.print(after);
writer.close();
no = d.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
valContext = new DOMValidateContext(new X509KeySelector(), no);
fac = XMLSignatureFactory.getInstance("DOM");
signature = fac.unmarshalXMLSignature(valContext);
JOptionPane.showMessageDialog(null, "Validation after convert: " + signature.validate(valContext));
}
}
package testevalidanfe;
import java.security.Key;
import java.security.PublicKey;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import javax.xml.crypto.AlgorithmMethod;
import javax.xml.crypto.KeySelector;
import javax.xml.crypto.KeySelectorException;
import javax.xml.crypto.KeySelectorResult;
import javax.xml.crypto.XMLCryptoContext;
import javax.xml.crypto.XMLStructure;
import javax.xml.crypto.dsig.SignatureMethod;
import javax.xml.crypto.dsig.keyinfo.KeyInfo;
import javax.xml.crypto.dsig.keyinfo.X509Data;
public class X509KeySelector extends KeySelector {
public KeySelectorResult select(KeyInfo keyInfo,
KeySelector.Purpose purpose,
AlgorithmMethod method,
XMLCryptoContext context)
throws KeySelectorException {
Iterator ki = keyInfo.getContent().iterator();
while (ki.hasNext()) {
XMLStructure info = (XMLStructure) ki.next();
if (!(info instanceof X509Data))
continue;
X509Data x509Data = (X509Data) info;
Iterator xi = x509Data.getContent().iterator();
while (xi.hasNext()) {
Object o = xi.next();
if (!(o instanceof X509Certificate))
continue;
final PublicKey key = ((X509Certificate)o).getPublicKey();
if (algEquals(method.getAlgorithm(), key.getAlgorithm())) {
return new KeySelectorResult() {
public Key getKey() { return key; }
};
}
}
}
throw new KeySelectorException("No key found!");
}
static boolean algEquals(String algURI, String algName) {
if ((algName.equalsIgnoreCase("DSA") &&
algURI.equalsIgnoreCase(SignatureMethod.DSA_SHA1)) ||
(algName.equalsIgnoreCase("RSA") &&
algURI.equalsIgnoreCase(SignatureMethod.RSA_SHA1))) {
return true;
} else {
return false;
}
}
}
For example, if the original XML starts with:
<nfeProc versao="1.10" xmlns="http://www.portalfiscal.inf.br/nfe">
<NFe xmlns="http://www.portalfiscal.inf.br/nfe">
<infNFe Id="NFe31090807301671000131550010001000216008030809" versao="1.10" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
...
doc4.asXML() return this:
<nfeProc xmlns="http://www.portalfiscal.inf.br/nfe" versao="1.10">
<NFe>
<infNFe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Id="NFe31090807301671000131550010001000216008030809" versao="1.10">
...
I had a closer look at this, and it turns out that DOM4J DOMWriter is doing something odd w.r.t. namespaces that obviously confuses the canonicalization process. I haven't pin pointed the exact reason, but I think it has to do with DOMWriter inserting extra xmlns attributes in the DOM elements. You can see the effect if you turn on logging for the XML digital signature API (as described in the article you refer to), the canonicalized <SignedInfo> element lacks namespace declaration in the DOM document produced by DOM4J.
However, instead of using DOMWriter, you can produce a DOM document by transformation, using a DOM4J DocumentSource and a DOMResult.
/**
* Create a DOM document from a DOM4J document
*/
static Document copy(org.dom4j.Document orig) {
try {
TransformerFactory tf = TransformerFactory.newInstance();
Transformer t = tf.newTransformer();
DOMResult result = new DOMResult();
t.transform(new DocumentSource(orig), result);
return (Document) result.getNode();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
Using the resulting DOM document, the validation works.