Using JavaFX to Call Remote (Web) Services (Accessing Web Services) Part 2

JSON Response Format

JSON is a very popular format on the Internet, especially in web applications where incoming data are parsed with JavaScript. JSON data are rather compact and more or less human readable.

A number of tools exist in Java for reading and writing JSON data. Unfortunately, at the time of writing there is no standard specification in Java that describes how to read and write JSON data. However, a Java Specification Request regarding JSON has been filed recently at www.jcp.org/en/ jsr/detail?id=353 with the title "JSR 353: Java API for JSON Processing." The description of this JSR reads as follows.

The Java API for JSON Processing (JSON-P) JSR will develop a Java API to process (for e.g. parse, generate, transform and query) JSON.

Once this JSR is accepted, there will be a uniform way in Java for dealing with JSON data. Until then, developers have to choose an existing JSON library or parse the data in their own code.

Each JSON library comes with its own set of tools, patterns, and advantages. Among the popular Java JSON libraries are

json.org (www.json.org/java/index.html)

jackson (http://jackson.codehaus.org/ )

jsonmarshaller (http://code.google.com/p/jsonmarshaller/)

json.simple (http://code.google.com/p/json-simple/)

In our examples, we use the jackson library. The other tools are able to achieve the same result, though. The Jackson JSON Processor is also used in a number of frameworks (e.g., Jersey, RESTeasy, Apache Camel, etc.).


We now replace the hard-coded list containing two fake tweets with real Tweets obtained via the REST-Twitter API with JSON response format. We keep the existing code, but we modify the getObservableList() method as shown in Listing 9-7.

Listing 9-7. Obtain Tweets Via the Twitter REST API, JSON Format and Parse the JSON

Obtain Tweets Via the Twitter REST API, JSON Format and Parse the JSON

 

 

 

 

 

Obtain Tweets Via the Twitter REST API, JSON Format and Parse the JSON

The code is a bit longer than in the case of the hard-coded tweets, and that is mainly because we do the JSON parsing ourselves. Later, we show how we can reduce the amount of code by using existing tools and libraries.

Before we dive into the code, we show the result of the modified application in Figure 9-5.

The result of the TweetApplication retrieving JSON data

Figure 9-5. The result of the TweetApplication retrieving JSON data

The code in Listing 9-7 can be divided into four parts:

1. Call the REST endpoint.

2. Obtain the raw JSON data.

3. Convert each item into a tweet.

4. Add the Tweets to the result.

Calling the REST endpoint is very straightforward:

tmp477_thumb

We create a URL Object that refers to the desired location, and pass that URL to the JsonFactory.createJsonParser method.

■ Note JsonFactory and JsonParser are specific to the Jackson JSON Parser. Other JSON libraries have other (factory) methods for calling endpoints.

We now have a JSON parser that contains a link to the data we want to have. Parsing these JSON data manually requires specific code for a specific case.

■ Note It is not our intention to deliver an exhaustive JSON parsing guide. We only try to show how JSON data can be parsed for our specific use case. You can easily find a number of tutorials on JSON on the Internet. For example, the Jackson JSON parser we are using here already comes with a number of tutorials and examples.

In Listing 9-5, we observe that the tweets are in an array named "results," starting with the left square bracket "[". By calling the JsonParser.next() method, we jump from one token to the next one. The following loop causes the JsonParser to jump until the first occurrence of an Array element.

tmp478_thumb

As long as we don't encounter the STOP_ARRAY token (the right square bracket "]") at this level, we know that we are processing the tweet results. Because parsing the individual tweets is a separate process, we isolated that in a specific parseTweet method.

In the parseTweet method, we create a Tweet instance and fill its fields based on what the JsonParser reads in the JSON data. We keep reading tokens until we encounter an END_OBJECT token at the same level at which we started. Our response contains nested elements inside a single tweet result, and thus we have to be careful not to stop parsing on the first END_OBJECT token. Listing 9-5 indeed shows a metadata field that contains an object as well. In order to make sure we keep parsing until we reach the end of the tweet information, we include the following loop.

tmp479_thumb

As you can see, there is a lot of information about individual tweets in the JSON response. For our example, we only need the author, the timestamp, and the content of the tweet. This information is present in the JSON response in the following format.

tmp4710_thumb

In the parseTweet() method, once we know we are not processing nested elements (e.g., the metadata element), we check the type of the current token. If that type is JsonToken.FIELD_NAME, we obtain the name of the field by calling

tmp4711_thumb

The token following the FIELD_NAME contains the information about the token. Hence, if the fieldName is "created_at", the next token will contain the value. Because we have all information in text format, we can call jp.getText() to obtain the information as a String.

The result of the parseTweet() method is a single Tweet. This tweet is added to the ObservableList by the following snippet.

tmp4712_thumb

This example shows that it is relatively easy to retrieve and parse JSON data obtained from a REST endpoint. However, the parsing is a bit cumbersome and error prone. Good-enough tools exist that help us out in this area. The Jackson JSON parser contains a JSON – Object mapper that directly binds text in JSON format to a Java Object.

Jackson supports Full Data Binding and Simple Data Binding. Full Data Binding allows the developer to read the incoming JSON data and automatically create a POJO. Simple Data Binding also reads and parses the incoming data, but the result is put in a Map rather than in a specific dedicated POJO.

■ Note The word "binding" in the jackson documentation should not be confused with the Binding concept in JavaFX.

Our next example uses the Simple Data Binding. Again, the only part of the code we have to change is the getObservableList() method. Listing 9-8 introduces the Simple Data Binding.

Listing 9-8. Obtain Tweets from JSON Response Using Simple Data Binding

 Obtain Tweets from JSON Response Using Simple Data Binding

As you can observe, the code has become much simpler, mainly because we don’t have to do the manual token processing anymore. The class that is helping us here is the org.codehaus.jackson.map.ObjectMapper.

The following code snippet creates a key-value Map based on the JSON response.

tmp4714_thumb

Each key in the Map points to an element in the response. The value corresponding to a key can be the simple value of the element, a list of elements, or a nested element.

We know that the element with key "results" is a list of tweets.

tmp4715_thumb

Therefore, the preceding snippet creates a list of tweets, with the information about a specific tweet in a specific Map<String, Object>.

We iterate over this list in order to obtain the specific information on the specific tweets. Each entry in the list contains a Map<String, Object> with the tweet-specific information (e.g., "created_at", "from_user", "text"). After parsing each individual tweet, we add it to the result.

The examples that we analyzed in this section show that we can easily call REST-based endpoints, and convert the resulting JSON response into a ListView. In the next section, we demonstrate a similar process for XML responses.

Next post:

Previous post: