JSF Troubleshooting
Created: 07.03.2017
JSF Troubleshooting
Troubleshooting in JSF is not that easy. Compared to desktop applications, web applications tend to have more error sources due to their client/server nature and the underlying communication protocols. While some errors are obvious and well described by error messages, other errors are hard to find and easy to overlook. Applying trial and error techniques to find bugs can be very frustration. Did you ever find yourself in a situation where you keep implementing small code changes leading to continuous redeployment? Did you ever insert System.out() statements in server-side code to check if methods are called? Did you ever made the right changes to fix a bug but your application server still didn’t get it right as it had an old version due to a deployment issue? I admit that all this stuff happened to me, especially when I’m under time pressure.
Wouldn’t it be cool, if there was a systematic way to find errors? I bet, such an approach will prevent frustration. In addition, it will help to understand JSF better.
Before I start to develop a systematic way to find errors in JSF applications, I would like to express my gratitude to a guy known as BalusC on Stackoverflow for providing a lot of insight in JSF. Most of the content in this artice is based on my experience with JSF in projects and his contributions that always turned out very useful.
Preparations
There are a few things that you can configure to make your life easier during development.
(1) Set the project to development mode
This property is set in the web.xml file that is parsed by your Java web container.
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
In general, this setting enables more detailed error messages including some JavaScript errors. However, it will also cost some performance. These error messages might be display in elements or at the console.
(2) Use <h:messages />
The element <h:messages /> is very useful as it is a container for all errors occuring in a certain view. I recommend to include this element in each facelets view while developing.
(3) Learn the JSF Lifecycle
Understanding the JSF lifecycle is crucial to spot certain errors. Validation errors, for example, are a common reason for unexpected behavior caused by the corresponding JSF lifecycle phase. You can find several articles on this subject:
- JSF lifecycle
- JSF lifecycle by BalusC
(4) Consider Blaming the Application Server for Weird Behavior
This is not a real preparation step. It is a hint that proved its value for troubleshooting.
In my experience, the application server is often the reason for weird behavior. During development, the server must endure constant deployment and a lot of updates that just don’t happen in a productive environment. Don’t let the application server fool you, if you cannot explain certain behavior by applying your knowledge, then blame the server first. Don’t get me wrong, I am very grateful for Java EE application servers. They are magnificent tools and most certainly whole teams of programmers invested a lot of effort to develop them. However, a lot of stuff can go wrong during redeployment. If you deploy a change and encounter weird behavior, try the following first:
- Remove the deployed applications and clean the server. In Eclipse, for example, you can do this via the Glassfish Tools (or whatever server you use).
- Empty the server cache by manually deleting its contents. In Glassfish, the OSGI-cache is in your domain directory.
- By the way, if you redeploy an application several times, the server might start slower and slower. Clearing the cache will probably help to speed the server up again.
(5) Log errors
This one might sound trivial. Don’t forget to catch exceptions and print the stacktrace to the console or some sort of logger. There is a special case when using threads. Exceptions occuring in threads might not get caught as the main thread already "passed by".
There are two possibilities to catch such exceptions occurring in threads:
(1) Use an UncaughtExceptionHandler as described in: http://stackoverflow.com/questions/6546193/how-to-catch-an-exception-from-a-thread
(2) Override the done() method that is called even if a thread "fails". The get() call will trigger every uncaught exceptions.
@Override
protected void done() {
super.done();
try {
get();
} catch (Exception e) {
e.printStackTrace();
}
}
The Diagnostic Scheme
The presented diagnostic scheme is not complete. It is based on experiences in smaller to medium sized projects. Please click on the box that best fits your problem.
View errors can be tracked down easy. They look like this and are directly displayed in a view file and the server log:
A server-side error is displayed in the console or the server logfile.
View Errors
View errors with error message
The class 'XY' does not have the property 'someProperty'
This error means that the ManagedBean does not have a setMethod that is named setSomeProperty(). Make sure that the names fit to the specified properties.
If you use Eclipse you can click anywhere in the ManagedBean and select "Generate getters and setters". This function will automatically create the methods.
Is an action supposed to happen?
Consider the following aspects before you move on:
Ajax behavior might be implicitly activated. While is non-ajax, from PrimeFaces uses ajax by default (you have to explicitely state ajax="false").
Nothing happens after pressing a <h:commandButton> or <h:commandLink>
There might be several problems. I try to list them by probability.
- Correct placement of <h:form> element
- Correct linking of action attribute to a method in a ManagedBean
Correct placement of <h:form> elements
<h:form> elements are a crucial part of every JSF application. Placing them right is very important to develop error free applications. Furthermore, they help to make Ajax requests efficient as they wrap partial information that is sent to the server.
JavaScript- and Ajax-related problems
Javasript, especially Ajax is not working:
Alot JSF implementations, for example RichFaces and PrimeFaces, rely on Javascript libraries (jQuery, …). In order to work correctly, they include these libraries by inserting import statements in the head section of the XHTML document. However, they require a element to integrate these lines before rendering.
Often, a <head> element is used in favor of the required <h:head> element.
Elements are not rendered after Ajax requests:
Ajax requests are wired to a remote action that is called and to elements that are re-rendered after the action is performed. For example, the textfield below is updated with the current time after the button is pressed.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<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:a4j="http://richfaces.org/a4j"
xmlns:rich="http://richfaces.org/rich"
xmlns:ui="http://java.sun.com/jsf/facelets">
<h:head>
<title>Example</title>
</h:head>
<h:body>
<h:form>
<a4j:commandButton value="getTime" render="textField"/>
</h:form>
<h:form>
<h:outputText id="textField" value="#{ajaxBean.time}"></h:outputText>
</h:form>
</h:body>
</html>
Use the correct attribute: As you can see the attribute is named render, not reRender as many tutorials state. I spent a lot of time on that simple fact, cause many tutorials state that new versions of Richfaces use reRender, which is just not true.
ManagedBean-related Problems
ManagedBeans are often easier to debug as they are more verbose and precise in terms of error messages. However, sometimes a ManagedBean is not even recognized as a ManagedBean or throws an error during injection.
Wrong Annotation Import
The chance is good that there is an Annotation error. Here is an example of older JSF annotations:
// wrong import
import javax.annotation.ManagedBean;
import javax.enterprise.context.RequestScoped;
// correct import
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped
@ManagedBean
@RequestScoped
And here an example of newer ones as the above is deprecated:
// wrong import
import javax.faces.bean.RequestScoped
// correct import
import javax.inject.Named;
import javax.enterprise.context.RequestScoped;
@Named
@RequestScoped
Forgot Serializable
Serialization is a mechanism for writing Java objects to some sort of "more cold" storage instead of the memory of your server. It can be used to preserve sessions or views as well as to free memory.
Handler classes should be serializable, at least the ones above RequestScoped, i.e. ViewScoped, SessionScoped, ApplicationScoped, ...
@Named
@SessionScoped
public class ProjectHandler implements Serializable {
}
Remember that everything in the handler (and recursively also their dependencies) needs to be serializable as well.