Trick JavaServer Faces, load your bean data from the client side

November 04, 2019

#java #tutorial #webdev #primefaces

Photo by Shawn Pang on Unsplash

Commonly we are using JavaServer Faces (JSF) to access to server-side data and logic but it might happen, that we would actually have to fetch data on the client side and would then have to inject these in our server managed beans.

For example, let’s imagine that your client absolutely want to display a random cute picture provided by the third party Dog API, which we are going to use in this article, in the application but that the server, where the Java application is running, have definitely no internet access despite trying to convince both company and server administrator, that it can’t be developed without internet access.

In such a special case and in a classical Swiss🇨🇭 way of resolving issue, you will probably then have to find a consensus and to implement a trick (or hack, depends if you see the glass half full or half empty 😉) as the one we are going to develop in this blog post.

Before We Start

To follow this solution you will need a Java project where both JSF and Primefaces are implemented. If you have none or if you would like to create a blank one, you could proceed as I displayed in my previous article “Create a Primefaces JSF project with Maven and Widfly”.

Getting Started

The first time I faced such a dead end as pictured above, I didn’t knew where to begin. After a bit of research I finally found out the cornerstone of the solution respectively the Primefaces <p:remotecommand/> which provides a simple way to execute backing bean methods with Javascript. Using it, we are able to send data from Javascript to the beans, decode these information and ultimately “convert” them in bean’s values.

Workflow

The workflow of the solution and the steps we are going to follow are the following:

  1. Fetch data from the 3rd party API using Javascript
  2. Pass the results from Javascript to the Java bean using <p:remotecommand/>
  3. Parse the information to actual bean object values
  4. Display the bean values on the client side
  5. Init the page with a data

Let’s get started 🚀

1. Fetch data from the 3rd party API using Javascript

To begin our implementation we are firstly creating a new page src/main/webapp/dogs.xhtml which contains a button, to trigger manually the start of our process, and the remote command. Both components have to be contained in a form.

Moreover we also add the actual implementation of the 3rd party API data fetching. For that purpose, we use the Javascript Fetch API.

<!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:p="http://primefaces.org/ui">
<h:head>
   <title>Random dog</title>
</h:head>
<h:body>

   <script type="text/javascript">
      const randomDog = async () => {
        const rawResponse =
          await fetch('https://dog.ceo/api/breeds/image/random');
        if (!rawResponse || !rawResponse.ok) {
           console.error(rawResponse);
          return;
        }
        const result = await rawResponse.text();
      };
  </script>

  <h:form>
     <p:remoteCommand name="loadResult"/>

     <p:commandButton value="Load a random dog"
                      onclick="randomDog();">
         <f:ajax execute="@form" render="@none" />
     </p:commandButton>
  </h:form>

</h:body>

</html>

2. Pass the results to the bean

You may have noticed that the above <p:button/> doesn’t classically call a bean action or listener but rather call immediately the Javascript function randomDog(); . It means that first of all, we are fetching the data from the client side. Therefore we should now to pass the results to the bean. For that purpose we create a new bean src/main/java/DogsBean.java which exposes a method load() in order to, guess what, load later one our data 😁.

import java.io.Serializable;
import javax.faces.view.ViewScoped;
import javax.inject.Named;

@Named("dogs")
@ViewScoped
public class DogsBean implements Serializable {
   public void load() {
      // TODO load the data to object values
   }
}

Our bean being ready, we could now improve our servlet respectively we link the <p:remotecommand/> with the bean load() method.

<h:form>
     <p:remoteCommand name="loadResult"
                      action="#{dogs.load()}"
                      process="@this" update="@form"/>
</h:form>

We complete the chain by calling the remote command with the result of the Javascript fetch 🤓 . For that purpose, we use the function created by the Primefaces remote command, identified with the name loadResult we provided, and we pass the information as a new JSON array containing an identifier, a name , and a value , the result of the fetch respectively the data as text.

<script type="text/javascript">
      // same code as above

      const result = await rawResponse.text();

      loadResult([{
        name: 'dog',
        value: result
      }]);
    };
</script>

This call will submit a new request to the server. We could therefore access the parameters of the request in our bean to find out the data we are interested in. These are identified with the identifier, the name we provided above respectively 'dog' .

public void load() {
   final String jsonData = FacesContext.getCurrentInstance()
                           .getExternalContext()
                           .getRequestParameterMap()
                           .get("dog");
}

3. Parse the information to bean object values

The data delivered by the Dog API are provided as JSON data, for example:

{
    "message": "https://images.dog.ceo/breeds/coonhound/n02089078_2794.jpg",
    "status": "success"
}

Therefore, in order to parse these to Java object values, we create a new corresponding data transfer object (DTO).

import java.io.Serializable;

public class DogDTO implements Serializable {

   private String message;
   private String status;

   public String getMessage() {
      return message;
   }
   public void setMessage(String message) {
      this.message = message;
   }
   public String getStatus() {
      return status;
   }
   public void setStatus(String status) {
      this.status = status;
   }
}

Having both data and Java object, we could now deserialize the information using the Google gson library which we add as a new dependency in our pom.xml .

<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>

We declare declare the above DTO as a member of the bean class and we effectively process the parsing of the data in our load() method.

import java.io.Serializable;
import javax.faces.context.FacesContext;
import javax.faces.view.ViewScoped;
import javax.inject.Named;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

@Named("dogs")
@ViewScoped
public class DogsBean implements Serializable {
   
   private DogDTO dog;

   public void load() {
      final String jsonData = FacesContext.getCurrentInstance()
                           .getExternalContext()
                           .getRequestParameterMap()
                           .get("dog");
      final Gson gson = new GsonBuilder().create();
      dog = gson.fromJson(jsonData, DogDTO.class);
   }

   public DogDTO getDog() {
      return dog;
   }
}

4. Display the bean values on the client side

We have now fetched data on the client side, sent these to the server but the user still don’t notice any results. For that reason we add a new image to our page which uses our DTO message variable as source.

<h:form>
     <p:outputPanel layout="block" rendered="#{dogs.dog != null}">
        <img src="#{dogs.dog.message}" alt="A random dog"/>
     </p:outputPanel>
</h:form>

That’s it, our implementation is ready. We could start our application server in a terminal to try out the solution.

mvn clean install && mvn wildfly:run

If everything goes according plan, we could open our application in our favorite browser at the address http://localhost:8080/jsf-dogs/dogs.xhtml and should now be able to fetch a random dog each time we call our action 😊

So much doggy 😍

5. Init the page with a data

This step isn’t mandatory but I think it’s interesting to notice that it is also possible to load data from the client side when the page is accessed. Basically, from the sever side, in our bean, we execute a Javascript function on the client side, once everything is loaded from the lifecycle PostContruct .

@PostConstruct
public void init() {
   PrimeFaces.current().executeScript("randomDog();");
}

That’s it, we dit it! We could restart our server and test our final implementation 🎉

An initial doggy and so much other doggy 😍

Cherry on the cake 🍒🎂

If you want to avoid the hassle of creating your own project and copying/pasting the above code, I have published the source code and project online on GitHub, be my guest and as always, I would be really happy to hear your feedback 😃

To infinity and beyond 🚀

David

Blog

Read the article

Interact With Your Audience With A Live Poll

December 5th 2019

#webdev #javascript #opensource #speaking

Read the article

Infinite Scroll with Ionic + React

December 2nd 2019

#programming #react #javascript #tutorial

Read the article

How to keep secret your Font Awesome Pro token in public GitHub actions

November 27th 2019

#devops #webdev #github #fontawesome

More articles

Address

Fluster GmbH c/o The Hub Zürich Association Sihlquai 131 8005 Zürich

On the web