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

Converting Web Services Data to TableView

So far, all our examples showed tweets in a ListView. The ListView is an easy and powerful JavaFX Control, however, there are other controls that are in some cases more suitable to render information.

We can show the Tweet data in a TableView as well, and that is what we do in this section. The retrieval and parsing of the data stay the same as in the previous example. However, we now use a TableView to render the data, and we have to define which columns we want to see. For each column, we have to specify the origination of the data. The code in Listing 9-16 shows the start method used in the example.

Listing 9-16. The Start Method in the Application Rendering Tweets in a TableView

The Start Method in the Application Rendering Tweets in a TableView

 

 

 

 

The Start Method in the Application Rendering Tweets in a TableView


 

Clearly, this example requires more code than the example showing a ListView. Setting up a table is slightly more complex, due to the different columns that are involved. There is not much difference between setting the contents of the ListView and setting contents of the TableView. This is achieved doing

tmp4739_thumb[2][2]_thumb

where the getObservableList() method is the same implementation as in the previous example.

When using a TableView, we have to define a number of TableColumns. This is done in the following code snippet.

tmp4740_thumb[2][2]_thumb

Using the TableColumn constructor, we create one TableColumn with title "Date", one with title "Author", and a third one titled "Text". The Generics <Tweet, String> indicate that each entry in a row represents a Tweet, and the individual cells in the specified column are of type String.

Next, the instances of TableColumn that we created need to know what data they should render. This is done using CellFactories, as shown in the following snippet.

tmp4741_thumb[2][2]_thumb

A detailed description of the setCellValueFactory method is beyond the scope of this topic. As can be observed from the example, we have to specify a Callback class with a call method that returns an ObservableValue containing the content of the specific cell. The tweet we are displaying in this row can be obtained via the CellDataFeatures instance that is passed in the call method. Because we want to show the timestamp, we return a SimpleStringProperty whose content is set to the timeStamp of the specified Tweet.

The same technique has to be used for the other TableColumns (containing the author and the title of the Tweet).

Finally, we have to add the columns to the TableView:

tmp4742_thumb[2][2]_thumb

Running this example results in the visual output shown in Figure 9-7.

Using a TableView for rendering tweets

Figure 9-7. Using a TableView for rendering tweets

This sample requires lots of boilerplate code for a simple table, but fortunately the JavaFX Platform contains a way to reduce the amount of code. Manually setting the CellValueFactory instances for each column is cumbersome, but we can use another method for doing this, by using JavaFX Properties. Listing 9-17 contains a modified version of the start method of the main class, where we leverage the JavaFX Properties concept.

Listing 9-17. Rendering Data in Columns Based on JavaFX Properties

Rendering Data in Columns Based on JavaFX Properties

This code is clearly shorter than the code in the previous sample. We actually replaced

tmp4745_thumb[2][2][2]

The same holds for the authorColumn and the textColumn.

We are using instances of javafx.scene.control.cell.PropertyValueFactory<S,T>(String name) for defining what specific data should be rendered in which cell.

The PropertyValueFactory searches for a JavaFX property with the specified name and returns the ObservableValue of this property when called. In case no property with such a name can be found, the JavaDoc says the following.

In this example, the "firstName" string is used as a reference to an assumed firstNameProperty() method in the Person class type (which is the class type of the TableView items list). Additionally, this method must return a Property instance. If a method meeting these requirements is found, then the TableCell is populated with this ObservableValue. In addition, the TableView will automatically add an observer to the returned value, such that any changes fired will be observed by the TableView, resulting in the cell immediately updating.

If no method matching this pattern exists, there is fall-through support for attempting to call get<property>0 or is<property>() (that is, getFirstName() or isFirstName() in the example above). If a method matching this pattern exists, the value returned from this method is wrapped in a ReadOnlyObjectWrapper and returned to the TableCell. However, in this situation, this means that the TableCell will not be able to observe the ObservableValue for changes (as is the case in the first approach above).

From this, it is clear that JavaFX Properties are the preferred way for rendering information in a TableView. So far, we used the POJO Tweet class with JavaBean getter and setter methods as the value object for being displayed in both a ListView and a TableView.

Although the example above also works without using JavaFX Properties, as stated by the JavaDoc, we now modify the Tweet class to use Properties for the author information. The timeStamp and the text fields could have been modified to use JavaFX Properties as well, but the mixed example shows that the fall-through scenario described in the JavaDoc really works. The modified Tweet class is shown in Listing 9-18.

Listing 9-18. Implementation of Tweet Class Using JavaFX Properties for the Author Field

Implementation of Tweet Class Using JavaFX Properties for the Author Field

 

 

 

 

Implementation of Tweet Class Using JavaFX Properties for the Author Field

 

Apart from the introduction of JavaFX Properties, there is another major change in the implementation of the Tweet class. The class is now annotated with

tmp4748_thumb[2][2][2]

The reason for this is that when doing so, the setter methods will be called by the JAXB.unmarshal method when it creates an instance of the Tweet with some specific information. Now that we are using JavaFX Properties instead of primitive types, this is required. The JAXB framework could easily assign the value of the XML Element "author" to the author String field, but it cannot assign a value to a JavaFX Property object by default.

By using XmlAccessType.PROPERTY, the setAuthor(String v) method will be called by the JAXB framework, supplying the value of the XML Element to the setAuthor method. The implementation of this method

tmp4749_thumb[2][2][2]

will then update the JavaFX Property that is subsequently being used by the TableColumn and the TableView.

The examples we have shown so far in this topic demonstrate that the Java Platform, Standard Edition, already contains a number of APIs that are very useful when accessing Web services. We also showed how to use the JavaFX Concurrent Framework, the ObservableList pattern, JavaFX Properties, and the PropertyValueFactory class in order to enhance the flow between calling the web service and rendering the data in the JavaFX Controls.

Although there is no rocket science involved in the examples, additional requirements will make things more complex, and more boilerplate code will be required. Fortunately, a number of initiatives already popped up in the JavaFX community, with the goal of making our lives easier.

Using External Libraries

With the exception of the JSON parser used in the first examples, all our examples so far did not require any additional external library. The Java 2 Platform, Standard Edition and the JavaFX Platform offer a great environment that can be used for accessing web services. In this section, we use three external libraries and show how they make accessing web services easier.

RestFX

The RestFX project is hosted at http://code.google.com/pZrestfx/ and that web site mentions the following mission statement.

REST/FX provides a set of classes for producing and consuming REST services in a JavaFX application.

RestFX contains implementations of Services that allow asynchronous access to web services, with Listeners that are notified when the State of the Service is changed. As such, it resembles Listing 9-15 where we created a primitive implementation of such a Service.

Using RestFX in our examples is very easy. Again, we only have to change the getObservableList() method, but for clarity we show the complete code of the main class here. Listing 9-19 shows how to retrieve tweets from the Twitter API with JSON output, and render them in a ListView.

Listing 9-19. Obtaining Tweets Using RestFX

Obtaining Tweets Using RestFX

 

Obtaining Tweets Using RestFX

The ObservableList creates a GetQuery and supplies the required information about the web services Endpoint. RestFX supports GetQuery, PostQuery, PutQuery, and DeleteQuery and as such it aligns very well with the REST specifications. When we want to execute the query, we have to specify an implementation of the QueryListener interface with a callback method that is called once execution is completed.

In our example, the result of the rest call is a JSON response, and similar to the jackson API we used in a previous example, the result is contained in a Map<String, Object>.

The "results" key in this Map corresponds with a List of Map<String, String> that contains information about a specific tweet. Querying this map allows us to construct a Tweet instance, and add it to the ObservableMap.

Being very much aligned with the REST/HTTP protocol, RESTFX provides APIs for easy manipulation of HTTP headers for Authentication, and for supplying query and form parameters. RESTFX uses the concept of "serializers" for translating content of a specific format into Java objects (e.g., Map). We used the JSON Serializer in our example, but RESTFX contains a number of other serializers (e.g., a CSVSerializer).

Next post:

Previous post: