JSON (JavaScript Object Notation) has emerged as a popular data format for HTML 5 and is often returned from web services. An ICEfaces or JSF developer can interact with these objects as well using some built-in utility classes. We'll be using ICEfaces 4 to demonstrate this approach.
The goal of this tutorial is to demonstrate retrieving a set of JSON data from the Google Maps API, parsing the result, and displaying distance on an XHTML page. Any JSON based service could be used, we stick to Google Maps for this tutorial because it is familiar to a lot of developers. Note that this tutorial is meant for more advanced developers who are familiar with creating an ICEfaces project, interacting with beans, XHTML pages, components, etc. As a result we won't step through some of the more basic steps.
We'll create a Managed Bean called "MapBean", this will be a mix of retrieving our JSON and storing the result. Generally you would split these functions into separate classes, but for the sake of demonstration we're using a single class.
MapBean.java
@ManagedBean(name=MapBean.BEAN_NAME)
@ViewScoped
public class MapBean implements Serializable {
public static final String BEAN_NAME = "mapBean";
private long distanceKm;
@PostConstruct
public void setupMapBean() {
}
public long getDistanceKm() {
return distanceKm;
}
public void setDistanceKm(long distanceKm) {
this.distanceKm = distanceKm;
}
}}
The basic skeleton of this class should look familiar. We will want to fill in the setupMapBean PostConstruct method to do our JSON lookup.
We will need the Google Maps API URL and an API key, which you can read more about here: https://developers.google.com/maps/
The general idea is to POST a request to https://maps.googleapis.com/maps/api/directions/json?key=KEY with an origin and destination. The response will be JSON formatted data that looks like this:
Google Maps JSON format
"routes" : [
{
"bounds" : {
"northeast" : {
"lat" : 53.5443901,
"lng" : -113.4833287
},
"southwest" : {
"lat" : 51.046964,
"lng" : -114.0708467
}
},
"copyrights" : "Map data ©2015 Google",
"legs" : [
{
"distance" : {
"text" : "299 km",
"value" : 298887
},
"duration" : {
"text" : "2 hours 53 mins",
"value" : 10364
},
...
To achieve this we'll use two utility classes: IOUtils (from Apache Commons) and JSONObject (from JSON.org). Normally we'd have to add these libraries to our project, but luckily for us they are included as part of the icefaces-ace.jar!
Specifically we can use:import org.icefaces.ace.json.JSONObject;import org.icefaces.apache.commons.io.IOUtils;
The methods used from these classes are the key takeaway from this tutorial, as with them you can retrieve and parse any JSON you need.
We'll fill in our setupMapBean method now to calculate the distance between Calgary and Edmonton, although any origin/destination set could be used by changing what is passed as URL parameters.
setupMapBean method
public void setupMapBean() {
InputStream urlStream = null;
try{
String gmapApiUrl = "https://maps.googleapis.com/maps/api/directions/json?key=KEY";
String url = gmapApiUrl + "&origin=Calgary&destination=Edmonton";
urlStream = new URL(url).openStream();
String retrievedContent = IOUtils.toString(urlStream);
JSONObject json = new JSONObject(retrievedContent);
JSONObject routes = json.getJSONArray("routes").getJSONObject(0);
JSONObject legs = routes.getJSONArray("legs").getJSONObject(0);
JSONObject distance = legs.getJSONObject("distance");
distanceKm = distance.getLong("value") / 1000l;
}catch (Exception failed) {
log.info("Failed to calculate distance: " + failed);
}finally {
if (urlStream != null) {
IOUtils.closeQuietly(urlStream);
}
}
}
As you can see we construct our Google Map API URL to POST to.
Then we use IOUtils to do the heavy lifting for us, which results in a String of un-parsed JSON. IOUtils will POST to the desired URL, and handle the response for us. Like all good utility classes this shields the developer from having to manage the stream, error codes, etc. themselves.
Finally we wrap the response in a JSONObject. We can use our knowledge of the returned format to drill down to the "distance" value we need, which we then set into our MapBean.distance variable. Basically from the JSON data we look into the "routes" array, the child of that being "legs", and an element of that being "distance".
We can simply display this "distanceKm" data on an XHTML page:
showDistance.xhtml
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:ui="http://java.sun.com/jsf/facelets"
xmlns:ace="http://www.icefaces.org/icefaces/components">
<h:head>
<title>Using JSON Tutorial</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>
</h:head>
<h:body>
<h:form>
<h:outputText value="Distance is #{mapBean.distanceKm}km"/>
<h:panelGroup layout="block">
<ace:gMap id="ourMap"
options="mapTypeControl: false, panControl: false, streetViewControl: false, zoomControl: false"
style="width: 800px; height: 600px; border: 5px inset black;">
<ace:gMapServices name="Directions" points="Calgary : Edmonton"/>
</ace:gMap>
</h:panelGroup>
</h:form>
</h:body>
</html>
This will render an ace:gMap component with directions shown and the distance (parsed from our JSON response from the Google Maps API) displayed.
Regardless of whether we're parsing Google Map JSON, or data from a weather service, stock ticker, location utility, etc. the techniques shown here are very useful to an ICEfaces developer.