Phil Webb's Blog

Random thoughts from a software developer

Archive for July 2011

Logging a full stacktrace in Spring Web Flow using a FlowExecutionListener

leave a comment »

One problem I sometimes encounter when using Spring Web Flow is that the root cause of exceptions get burred so deep that they are not always logged.

For example, say you have an end-state that calls a bean method, and that method throws an exception:

<end-state id="finish">
    <output name="result" value="someBean.processFinalResultAndSometimesThrow()">

You will probably end up with a log entry like this:

org.springframework.webflow.engine.FlowOutputMappingException: Errors occurred during output mapping in state 'finish' of flow 'exampleFlow'; errors = [[SourceAccessError@3f3a3f3a mapping = someBean.processFinalResultAndSometimesThrow(), code = 'evaluationException', error = true, errorCause = org.springframework.binding.expression.EvaluationException: An ELException occurred getting the value for expression 'someBean.processFinalResultAndSometimesThrow()' on context [class org.springframework.webflow.engine.impl.RequestControlContextImpl], originalValue = [null], mappedValue = [null]]]

We get information about the flow and the state where the error occurred, we even get the bean method that was called, but we don’t have a complete stack trace of the actual root cause. Luckily for us the root cause is available and to log it you need to do is write a FlowExecutionListener:

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.binding.mapping.MappingResult;
import org.springframework.stereotype.Component;
import org.springframework.webflow.engine.FlowAttributeMappingException;
import org.springframework.webflow.execution.FlowExecutionException;
import org.springframework.webflow.execution.FlowExecutionListenerAdapter;
import org.springframework.webflow.execution.RequestContext;

public class LoggingFlowExecutionListener extends FlowExecutionListenerAdapter {
    private final Log logger = LogFactory.getLog(getClass());

    public void exceptionThrown(RequestContext context, FlowExecutionException exception) {
        if (exception instanceof FlowAttributeMappingException) {
            List<MappingResult> errors = ((FlowAttributeMappingException)exception).getMappingResults().getErrorResults();
            for (MappingResult error : errors) {
                if (error.getErrorCause() != null) {
                    logger.warn("FlowAttributeMappingException thown containing error : " + error.getErrorCause(), error.getErrorCause());

Attach the listener in usual web flow way and all exceptions will be logged, complete with full stack trace.

Written by Phillip Webb

July 11, 2011 at 1:56 pm

Posted in Web Flow

Integrating Spring & JavaServer Faces : Dynamic Navigation

leave a comment »

Often your JSF application will need to move beyond basic static navigation and start to make dynamic navigation decisions.  For example, you may want to redirect users based on their age.  Most JSF tutorials recommend that dynamic navigation is implemented by binding the action attribute of a command to a backing bean:

<h:commandButton action="#{bean.actionBasedOnAge}"/>
public String actionBasedOnAge() {
  if(age &lt; 12) {
    return "fetchadult";
  } else {
    return "ok"

The example above shows how anyone under twelve is directed to 'fetchadult' instead of the usual 'ok'. Both the 'fetchadult' and 'ok' outcomes will need to have navigation rules defined in the faces-config.xml so that JSF knows what actual page to display.

When working with Spring MVC it is often more natural to have navigation logic contained in the @Controller bean. To help with this, implicit 'controller' and 'handler' variables are available when rendering JSF from MVC. The 'controller' variable provides access to the controller bean that was mapped to the original request, and the 'handler' variable to the underling MVC handler.  In Spring 3.0 'controller' and 'handler' are generally the same object. In Spring 3.1 however, the underlying MVC architecture is changing and 'handler' will generally be a org.springframework.web.method.HandlerMethod instance.

Here is a submit button that references the someNavigation() method of the the @Controller:

<h:commandButton action="#{controller.someNavigation"/>

Whilst accessing the controller bean is useful, it is not the ideal solution.  I prefer to use logical names in my JSF pages and map those the Java methods.  I also want an easy way to get back to data from the underlying model.

The @NavigationMapping annotation provides another, more flexible approach to handling navigation.  It works in a very similar way to @RequestMappings.  The annotation can be placed on any public method in your @Controller to map navigation outcomes to destinations.

<h:commandButton action="submit"/>
public String onSubmit() {
  return "redirect:";

If you need access to a backing bean the standard Spring @Value annotation can be used.  Any EL expression that the page can resolve can also be used on a navigation method parameter.

public String onSubmit(@Value("#{person.age}") int age) {

Accessing model elements is even easier.  As long as you only have a single object of the type you want to access in your model, and it is not a simple type (int, String, etc), you don’t need any annotations:

public String onSubmit(Person p) {

Other argument types can also be used (see the JavaDoc for a complete list).  For example, here is a navigation mapping that handles 'submit', 'cancel' and 'save' outcomes.  The injected arguments tell us the which of the three outcomes was clicked and provides access to the source UIComponent.

public String handleNavigation(String outcome, UIComponent source) {

Return types are also equally flexible.  You can return view names as Strings, you can also use the same "" notation that I have previously blogged about.  You can also return View objects directly or you can use NavigationOutcome if you want to include implicit model items.

Finally, if you just want to render an immediate response you can use the @ResponseBody annotation or return a HttpEntity.  This works in exactly the same way as Spring.

Written by Phillip Webb

July 1, 2011 at 7:56 pm