How JSF Works and how to Debug it - is polyglot an alternative?
JSF is not what we often think it is. It's also a framework that can be somewhat tricky to debug, specially when first encountered. In this post let's go over on why that is and provide some JSF debugging techniques. We will go through the following topics:
- JSF is not what we often think
- The difficulties of JSF debugging
- How to debug JSF systematically
- How JSF Works - The JSF lifecycle
- Debugging an Ajax request from browser to server and back
- Final thoughts - alternatives? (questions to the reader)
JSF is not what we often think
The difficulties of JSF debugging
When comparing JSF to GWT and AngularJS in a previous post, I found that the (most often used) approach that the framework takes of abstracting HTML and CSS from the developer behind XML adds to the difficulty of debugging, because it creates an extra level of indirection.
The only way to debug JSF systematically
When first encountering JSF, I first tried to approach it from a Java, XML and documentation only. While I could do a part of the work that way, there where frequent situations where that approach was really not sufficient.
The conclusion that I got to is that in order to be able to debug JSF applications effectively, an understanding of the following is needed:
- Chrome Dev Tools, Firebug or equivalent
- The JSF Lifecycle
This might sound surprising to developers that work mostly in Java/XML, but this web-centric approach to debugging JSF is the only way that I managed to tackle many requirements that needed some significant component customization, or to be able to fix certain bugs.
Let’s start by understanding the inner workings of JSF, so that we can debug it better.
The JSF take on MVC
The way JSF approaches MVC is that the whole 3 components reside on the server side:
The Model is a tree of plain Java objects
The View is a server side template defined in XML that is read to build an in-memory view definition
The Controller is a Java servlet, that receives each request and processes them through a series of steps
The browser is assumed to be simply a rendering engine for the HTML generated at server side. Ajax is used for submitting parts of the page for server processing, and to request the server to ‘repaint’ only portions of the screen, without navigating away from the page.
The JSF Lifecycle
Once an HTTP request reaches the backend, it gets caught by the JSF Controller that will then process it. The request goes through a series of phases known as the JSF lifecycle, which is essential to understand how JSF works:
Design Goals of the JSF Lifecycle
The whole point of the lifecycle is to manage MVC 100% on the server side, using the browser as a rendering platform only.
The initial idea was to decouple the rendering platform from the server-side UI component model, in order to allow to replace HTML with alternative markup languages by swapping the Render Response phase.
So let’s go through each phase and see how to debug it if needed, starting in the browser. Let's base ourselves in a simple example that uses an Ajax request.
A JSF 2 Hello World Example
The following is a minimal JSF 2 page, that receives an input text from the user, sends the text via an Ajax request to the backend and refreshes only an output label:
JSF 2.2 Hello World Example
The page looks like this:
Following one Ajax request - to the server and back
Let’s click submit in order to trigger the Ajax request, and use the Chrome Dev Tools Network tab (right click and inspect any element on the page).What goes over the wire? This is what we see in the Form Data section of the request:
j_idt8:input: Hello World javax.faces.ViewState: -2798727343674530263:954565149304692491 javax.faces.source: j_idt8:j_idt9 javax.faces.partial.event: click javax.faces.partial.execute: j_idt8:j_idt9 j_idt8:input javax.faces.partial.render: j_idt8:output javax.faces.behavior.event: action javax.faces.partial.ajax:true
This request says:
The new value of the input field is "Hello World", send me a new value for the output field only, and don't navigate away from this page.
Let's see how this can be read from the request. As we can see, the new values of the form are submitted to the server, namely the “Hello World” value. This is the meaning of the several entries:
javax.faces.ViewStateidentifies the view from which the request was made.
- The request is an Ajax request, as indicated by the flag
- The request was triggered by a click as defined in
But what are those
j_ strings ? Those are space separated generated identifiers of HTML elements. For example this is how we can see what is the page element corresponding to
j_idt8:input, using the Chrome Dev Tools:
There are also 3 extra form parameters that use these identifiers, that are linked to UI components:
javax.faces.source: The identifier of the HTML element that originated this request, in this case the Id of the submit button.
javax.faces.execute: The list of identifiers of the elements whose values are sent to the server for processing, in this case the input text field.
javax.faces.render: The list of identifiers of the sections of the page that are to be ‘repainted', in this case the output field only.
But what happens when the request hits the server ?
JSF lifecycle - Restore View Phase
Once the request reaches the server, the JSF controller will inspect the
javax.faces.ViewState and identify to which view it refers. It will then build or restore a Java representation of the view, that is somehow similar to the document definition in the browser side.
The view will be attached to the request and used throughout. There is usually little need to debug this phase during application development.
JSF Lifecycle - Apply Request Values
The JSF Controller will then apply to the view widgets the new values received via the request. The values might be invalid at this point. Each JSF component gets a call to it’s
decode method in this phase.
This method will retrieve the submitted value for the widget in question from the HTTP request and store it on the widget itself.
To debug this, let’s put a breakpoint in the
decode method of the
HtmlInputText class, to see the value “Hello World”:
Notice the conditional breakpoint using the HTML
clientId of the field we want. This would allow to quickly debug only the decoding of the component we want, even in a large page with many other similar widgets. Next after decoding is the validation phase.
JSF Lifecycle - Process Validations
In this phase, validations are applied and if the value is found to be in error (for example a date is invalid), then the request bypasses Invoke Application and goes directly to Render Response phase.
To debug this phase, a similar breakpoint can be put on method
processValidators, or in the validators themselves if you happen to know which ones or if they are custom.
JSF Lifecycle - Update Model
In this phase, we know all the submitted values where correct. JSF can now update the view model by applying the new values received in the requests to the plain Java objects in the view model.
This phase can be debugged by putting a breakpoint in the
processUpdates method of the component in question, eventually using a similar conditional breakpoint to break only on the component needed.
JSF Lifecycle - Invoke Application
This is the simplest phase to debug. The application now has an updated view model, and some logic can be applied on it.
This is where the action listeners defined in the XML view definition (the 'action' properties and the listener tags) are executed.
JSF Lifecycle - Render Response
This phase can be debugged using breakpoints in the
encodeEnd methods of the component in question.
The components will either render themselves or delegate rendering to a
Back in the browser
It was a long trip, but we are back where we started! This is how the response generated by JSF looks once received in the browser:
Using the Id of the update, the client side JSF callback will search for a component with that Id, delete it from the document and replace it with the new updated version.
In this case, "Hello World" will show up on the label next to the Input text field!
The Chrome Dev Tools can help debug the client part. For example let’s say that we want to halt the client when an Ajax request is triggered. We need to go to the sources tab, add an XHR (Ajax) breakpoint and trigger the browser action. The debugger will stop and the call stack can be examined:
To solve this, download the source code of the library and do a non minified build of the jar. There are usually instructions for this, otherwise check the project poms. This will install in your Maven repository a jar with non minified sources for debugging.
The UI Debug tag:
ui:debug tag allows to view a lot of debugging information using a keyboard shortcut, see here for further details.
JSF is very popular in the enterprise Java world, and it handles a lot of problems well, specially if the UI designers take into account the possibilities of the widget library being used.
Is polyglot an alternative?
We can wonder that if developers have to know a fair amount about web technologies in order to be able to debug JSF effectively, then it would be simpler to build enterprise front ends (just the client part) using those technologies directly instead.
Conclusions and some questions if you have the time
Thanks for reading, please take a moment to share your thoughts on these matters on the comments bellow:
Did you find one of the GWT-based frameworks (plain GWT, Vaadin, Errai), or the Play Framework to be easier to use and of better productivity?