Wednesday, December 21, 2011

Automatic to-Object conversion in JSF selectOneMenu & Co.

When creating a web UI, there is often the need to let a user make a selection from e.g. a drop-down. The items in such a drop-down are not rarely backed by domain objects. Since these items in the HTML rendering are just simple character identifiers, we need some way to encode the object version of an item to this simple character identifier (its string representation) and back again.

A well established pattern in JSF is the following:

<selectOneMenu value="#{bean.selectedUser}" converter="#{userConverter}">
    <selectItems value="#{bean.selectableUsers}" var="user" itemValue="#{user}" itemLabel="#{user.name}" />
</h:selectOneMenu>

With userConverter defined as something like:

@Named
public class UserConverter implements Converter {

    @Inject
    private UserDAO userDAO;

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {
        return userDAO.getById(Long.valueOf(value));
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return ((User) value).getId().toString();
    }
}
(note that the converter implementation is overly simplified, in practice null checks and checks for "String value" representing a number would be needed)

This is functional, but in its full form not really convenient to program nor efficient. Upon every post back, there will be a call to the DAO to convert the string representation of an item back to its Object form. When no caching is used or the object isn't in the cache, this will likely result in a call to a back-end database, which is never a positive contribution to the overall performance of a page. It gets worse when there are more of such conversions being done and it can go through the roof when we have e.g. editable tables where each row contains multiple drop-downs. A table with only 10 rows and 4 drop-downs might result in 40 separate calls to the back-end being done.

But is using a DAO here really needed?

After all, after the converter does its work, JSF checks whether the Object is equal to any of the Objects in the collection that was used to render the drop-down. In other words, the target Object is already there! And it must be there by definition, since without it being present validation will simply never pass.

So, by taking advantage of this already present collection we can prevent the DAO calls. The only question is, how do we get to this from a converter? A simple way is to use a parameter of some kind and provide it with a binding to this collection. This is however not really DRY, as it means we have to bind to the same collection twice right after each other (once for the selectItems, once for the converter parameter). Additionally, we still have to iterate over this and need custom code that knows to which property of the Object we need to compare the String value. For instance, for our User object we need to convert the String value to a Long first and then compare it with the Id property of each instance.

Another approach that I would like to present here is basically emulating how a UIDataTable detects on which row a user did some action. After the post back it iterates over the data that was used to render the table in the same way again. This will cause the same IDs to be generated as in the original rendering. The ID of the component that is posted back is compared to the newly generated one and when they match iteration stops and we know the row.

In this case, after the post back we'll iterate over all select item values, convert these to their string representation and compare that to the 'to-be-converted' string value. If they match, the unconverted object is the one we're after and we return that. For iterating over the select item values, I took advantage of a private utility class that's in Mojarra: com.sun.faces.renderkit.SelectItemsIterator (for a proof of concept, I just copied it since it's package private).

The implementation is done via a Converter base class from which user code can inherit. That way, only a getAsString method needs to be implemented:

@Named
public class UserConverter extends SelectItemsBaseConverter {
    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        return ((User) value).getId().toString();
    }
}

The base class is implemented as follows:

public abstract class SelectItemsBaseConverter implements Converter {
    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String value) {        
        return SelectItemsUtils.findValueByStringConversion(context, component, value, this);    
    }    
}

And the SelectItemsUtils class:

public final class SelectItemsUtils {
    
    private SelectItemsUtils() {}

    public static Object findValueByStringConversion(FacesContext context, UIComponent component, String value, Converter converter) {
        return findValueByStringConversion(context, component, new SelectItemsIterator(context, component), value, converter);        
    }
    
    private static Object findValueByStringConversion(FacesContext context, UIComponent component, Iterator<SelectItem> items, String value, Converter converter) {
        while (items.hasNext()) {
            SelectItem item = items.next();
            if (item instanceof SelectItemGroup) {
                SelectItem subitems[] = ((SelectItemGroup) item).getSelectItems();
                if (!isEmpty(subitems)) {
                    Object object = findValueByStringConversion(context, component, new ArrayIterator(subitems), value, converter);
                    if (object != null) {
                        return object;
                    }
                }
            } else if (!item.isNoSelectionOption() && value.equals(converter.getAsString(context, component, item.getValue()))) {
                return item.getValue();
            }
        }        
        return null;
    }

    public static boolean isEmpty(Object[] array) {
        return array == null || array.length == 0;    
    }

    /**
     * This class is based on Mojarra version
     */
    static class ArrayIterator implements Iterator<SelectItem> {

        public ArrayIterator(SelectItem items[]) {
            this.items = items;
        }

        private SelectItem items[];
        private int index = 0;

        public boolean hasNext() {
            return (index < items.length);
        }

        public SelectItem next() {
            try {
                return (items[index++]);
            }
            catch (IndexOutOfBoundsException e) {
                throw new NoSuchElementException();
            }
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
    }
}

The source of the Mojarra SelectItemsIterator can be found here, MyFaces seems to have a similar implementation here, but I did not test that one yet. PrimeFaces also has something like this (see org.primefaces.util.ComponentUtils#createSelectItems).

A custom selectOneMenu, selectManyListbox etc could even go a step further and should be able to do this without the need for a converter at all. Combined with an extended selectItems tag, it could look like this:

<selectOneMenu value="#{bean.selectedUser}">
    <selectItems value="#{bean.selectableUsers}" var="user" itemValue="#{user}" itemValueAsString="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>

In this hypothetical example, we could even simplify stuff further by setting itemValue by default to var, so it would then look like this:

<h:selectOneMenu value="#{bean.selectedUser}">
    <f:selectItems value="#{bean.selectableUsers}" var="user" itemValueAsString="#{user.id}" itemLabel="#{user.name}" />
</h:selectOneMenu>

Implementing this might be the topic for a next article. For now I'll hope the converter based approach is useful.

An implementation of this is readily available in the new OmniFaces library, from where you can find the documentation and the full source code. There's also a live demo available.

Arjan Tijms

Sunday, September 18, 2011

Single class pure Java JSF application

In my previous blog entry, Authoring JSF pages in pure Java, it was explained how to set up a JSF based web application using nothing but pure Java. No XML based templating (Facelets) was required and the view was build purely programmatically.

I got one remark though that the example code did used expression language (EL) to patch some of the parts together. Although EL is really convenient, as it provides a way to point to a (nested) method on a scoped object, it's not regular type-safe Java.

Luckily, the Java component API of JSF doesn't only use EL based ValueExpressions and MethodExpressions, but also allows regular Java types to be set as listeners and values. This is demonstrated in the code below. While at it, I've done away with the separate backing bean for this example and let the same class that defines the page handle the action event.

The result is a pure Java, xml-less, EL-less, config-less, single class JSF application [phew]:

@Named
@FacesConfig
public class Intro implements Page, ActionListener {

    private HtmlOutputText message;
    
    @Override
    public void buildView(FacesContext context, UIViewRoot root) throws IOException {
        
        List rootChildren = root.getChildren();
        
        UIOutput output = new UIOutput();
        output.setValue("<html xmlns="http://www.w3.org/1999/xhtml">");                
        rootChildren.add(output);
        
        HtmlBody body = new HtmlBody();
        rootChildren.add(body);
        
        HtmlForm form = new HtmlForm();
        body.getChildren().add(form);
        
        message = new HtmlOutputText();
        form.getChildren().add(message);
        
        HtmlCommandButton actionButton = new HtmlCommandButton();
        actionButton.addActionListener(this);
        actionButton.setValue("Do action");
        form.getChildren().add(actionButton);
                
        output = new UIOutput();
        output.setValue("</html>");
        rootChildren.add(output);
    }
    
    @Override
    public void processAction(ActionEvent event) throws AbortProcessingException {
        message.setValue("hello, world");
    }    
}

To run this on Payara, only this class and the small (8,980 bytes) javavdl.jar library are required:

After requesting localhost:8080/demo/intro.jsf, a single button will be shown. The message "hello, world" will be displayed when this button is clicked.

Interesting to note perhaps is that the components themselves only exist for the duration of the request and after every post-back the component tree will be re-created. State set on the components during buildView will be marked as the so-called initial state and will typically not be taken into account by JSF's state saving mechanism. Since only the HtmlCommandButton in the example code references the Page instance after this buildView it will effectively have request scope.

The java based vdl is still rather simple, so it's still just a proof of concept. I've planned some enhancements that I'll work on soon if time permits (e.g. perhaps support for scopes other than request scope without using EL). Stay tuned!

Arjan Tijms

Monday, September 12, 2011

Authoring JSF pages in pure Java

JSF is well known as a server side web framework to build a web application's UI with the help of components. For the overwhelming majority of users those components are represented by the tags one uses to compose a page, be it via JSP or Facelets.

The following is a typical example of a page authored with Facelets:

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">    
    <h:body>   
       #{backingBean.hello}   
        <h:form>      
            <h:inputText value="#{backingBean.name}" />                    
            <h:commandButton value="Say Hello" action="#{backingBean.sayHello}" />
        </h:form>        
    </h:body>
</html>

This may give the impression that JSF components *are* the tags shown above, and thus that JSF is necessarily about tags and XML. That is however not true.

JSF has always had a clear separation between the technology used to author pages (the so-called view description language) and the actual API to create components and compose them together into a component tree. This API is a Java API that even in the very first days of JSF had no knowledge whatsoever about JSP or tags. The strict separation allowed alternative view declaration languages like Facelets to be created and eventually be promoted to the default VDL, without needing to change the underlying JSF core framework.

Other view declaration languages have been created as well. One notable example is a concept based on JavaFX, in which a JSF page would look like this:

var x = 0;
var bindVal = "Hello";
 
function init(){
   FxPage{
      content : [
         FxForm{
                content : [
                    FxOutputLabel{
                        value : bind bindVal
                    },
                    FxCommandButton{
                        value : "Button"
                        actionListener : function() : String{
                            bindVal = "Hello {x++}";
                            return null;
                        }
                    }
                ]
            }
        ]
    }
}
See: JavaFX as JSF VDL (View Description Language)?

As it appears, the API to create components and compose a component tree is pretty accessible by itself. It could theoretically be used directly to author pages instead of solely being used as an API for VDL implementations. The problem however is that it's not clear how to actually start doing that. One trick is to use dynamic tree manipulation and add components in a PreRenderView event on an otherwise empty page.

Another way is to create a minimal VDL implementation. As a proof of concept, that's what I did. With such a thing it's possible to create a JSF application completely in Java. No Facelets or JSP files, and following Minimal 3-tier Java EE app, without any XML config, no web.xml or faces-config.xml is required either. There doesn't even have to be a WEB-INF or WebContent directory in the project.

The following shows a JSF page being defined in pure Java:

public class Intro implements Page {

    @Override
    public void buildView(FacesContext context, UIViewRoot root) throws IOException {

        ELContext elContext = context.getELContext();
        ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
        
        List<UIComponent> rootChildren = root.getChildren();
        
        UIOutput output = new UIOutput();
        output.setValue("<html xmlns="http://www.w3.org/1999/xhtml">");                
        rootChildren.add(output);
        
        HtmlBody body = new HtmlBody();
        rootChildren.add(body);
        
        HtmlForm form = new HtmlForm();
        body.getChildren().add(form);
        
        ValueExpression messageProperty = expressionFactory.createValueExpression(elContext, "#{myBean.message}", String.class);
        
        HtmlOutputText message = new HtmlOutputText();
        message.setValueExpression("value", messageProperty);
        form.getChildren().add(message);

        MethodExpression helloMethod = expressionFactory.createMethodExpression(elContext, "#{myBean.action}", Void.class, new Class[0]);
        
        HtmlCommandButton hiCommand = new HtmlCommandButton();
        hiCommand.setActionExpression(helloMethod);
        hiCommand.setValue("Say hello");
        form.getChildren().add(hiCommand);
        
        MethodExpression navigateMethod = expressionFactory.createMethodExpression(elContext, "#{myBean.navigate}", String.class, new Class[0]);
        
        HtmlCommandButton navigateCommand = new HtmlCommandButton();
        navigateCommand.setActionExpression(navigateMethod);
        navigateCommand.setValue("Do navigation");
        form.getChildren().add(navigateCommand);
                
        output = new UIOutput();
        output.setValue("</html>");
        rootChildren.add(output);
    }    
}

This will be rendered as follows:

The code shows how components are created simply by using the new operator and a tree is created by just inserting the child components in the children collections of their parents. Action listeners are registered on action source components by setting a method expression that points to the scoped backing bean "myBean", which is defined as follows:

@Named
@FacesConfig
public class MyBean {

    private String message;

    public void action() {
        message = "Hi!";
    }
    
    public String navigate() {
        return redirectOutcome(OtherPage.class);
    }
    
    public String getMessage() {
        return message;
    }    
}

Note that the bean features a navigation method that uses the class type of the target page to determine the navigation outcome.

By putting stuff in base classes or utility methods, page implementations can be simplified. For instance, the following shows the page where the user is navigated to after pushing the button on the first page. It inherits from a base class that already defines the html and outer body part, and only implements the body content:

public class OtherPage extends BodyTemplate {

    @Override
    public void buildBody(FacesContext context, HtmlBody body) {    
        HtmlOutputText output = new HtmlOutputText();
        output.setValue("This is a new page.");
        body.getChildren().add(output);        
    }
}

This page is rather simple and is rendered as:

As shown by the screen shots, if the project is called javavdl the initial page can be requested by requesting http://localhost/javavdl/intro.jsf, which is fully implemented using the Intro.java class given above. After clicking the navigate button, the user will be redirected to http://localhost/javavdl/test/otherPage.jsf, which is fully implemented by OtherPage.java. For this simple proof of concept, classes implementing pages have to reside in the package resources.javavdl.pages. Sub-packages in that package become paths relative to the deployment root of the application. E.g. /test/otherPage.jsf is implemented by resources.javavdl.pages.test.OtherPage.

The following is a picture of my workspace, showing that there is absolutely not a single xml file:

If this were used for real, the "src" package would probably be in a jar, and the application would consist of nothing more than this jar and the four classes shown in the demo package.

The current setup is really just a proof of concept. I personally think a declarative approach like Facelets is actually clearer, although some people actually do seem to like a purely programmatic approach to building a UI.

If people want to tinker with this, I've shared my Eclipse project where I implemented this here: github.com/arjantijms/javavdl (it currently depends on the Glassfish WTP server adapter being installed).

Arjan Tijms

Sunday, September 4, 2011

Simple Java based JSF custom component

Even though in JSF components have always been a central thing, actually creating them required a ridiculous amount of tedious work in JSF 1.x. Not only did you had to create the actual component, it also required you to:
  • Register the component in an XML file
  • Create a tag handler class, where you referenced the component by its registered name
  • Register the tag in .tld file.

You were also more or less supposed to create a separate renderer class, and although this actually has always been optionally, people seemed to interpret it as being a required part as well. Although none of this was really difficult, the sheer amount of work prevented everyone but component library builders from creating components.

JSF 2.0 addressed all of these concerns by introducing composite components, where you are able to create first-class components just by putting some existing components and/or markup in a Facelets file. For the majority of use cases where application builders needed their own customized components, this is actually all that's needed.

For some cases however a Java based component is still a more natural fit. Although not as simple to create as composite components, creating Java based custom components has actually been simplified as well. Of the steps outlined above, only a registration for the tag is still required. The actual component can be rather simple:

components/CustomComponent.java

@FacesComponent("components.CustomComponent")
public class CustomComponent extends UIComponentBase {

    @Override
    public String getFamily() {        
        return "my.custom.component";
    }
    
    @Override
    public void encodeBegin(FacesContext context) throws IOException {
        
        String value = (String) getAttributes().get("value");
        
        if (value != null) {        
            ResponseWriter writer = context.getResponseWriter();
            writer.write(value.toUpperCase());
        }
    }
}

Unfortunately, a registration in an XML file is still required in JSF 2.1 to use this as a tag (note, that in JSF 2.2 this isn't required anymore):

META-INF/my.taglib.xml

<?xml version="1.0" encoding="UTF-8"?>
<facelet-taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facelettaglibrary_2_0.xsd"
    version="2.0">

    <namespace>http://example.com/test</namespace>
    
    <tag>
        <tag-name>customComponent</tag-name>
 <component>
            <component-type>components.CustomComponent</component-type>
        </component>
    </tag>
    
</facelet-taglib>

The custom component can now be used on a Facelet as follows:

page.xhtml

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:test="http://example.com/test"
>
    <h:body>     
        <test:customComponent value="test"/>        
    </h:body>
</html>

As shown, creating a Java based JSF component that simply renders something is not that complicated. Although composite components should generally be preferred, Java based ones can come in handy and it's an important extra tool.

It's a shame perhaps the XML registration is still needed in JSF 2.1, but luckily there was a feature request in the JSF spec JIRA that made it largely unnecessary for JSF 2.2. Hopefully the actual Java code can also be further simplified if the family and component name would be defaulted in a future JSF version (the last e.g. to the fully qualified class name).

Arjan Tijms

Sunday, August 21, 2011

Minimal 3-tier Java EE app, without any XML config

Older versions of Java EE and Java frameworks in general were rather heavy with regard to required XML for configuration. Notorious were EJB2, Spring 2.x, JSF 1.x, Servlet 2.5 and many more.

These days things have improved quite a lot. In this post I'll demonstrate a very simple, yet 3-tiered, Hello word application for Java EE. It uses JSF 2.1 and EJB 3.1 and absolutely not a single line of XML configuration.

The entire application consists of just 3 files: page.xhtml, BackingBean.java and BusinessBean.java. To run the application, create a dynamic web project called 'mytest' in Eclipse (EE edition) and delete everything that's generated by default in WebContent. Copy page.xhtml to WebContent and copy both .java files to src. Add the app to your server (e.g. Payara 164) and browse to localhost:8080/mytest/page.jsf to see all the action.

The following shows the code of the 3 files involved:

page.xhtml

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:jsf="http://xmlns.jcp.org/jsf">
    <body>
        #{backingBean.hello}

        <form jsf:id="form">
            <input type="text" jsf:value="#{backingBean.name}" />
            <input type="submit" value="Say Hello" jsf:action="#{backingBean.sayHello}" /> 
        </form>
    </body>
</html>

BackingBean.java

import javax.ejb.EJB;
import javax.faces.bean.ManagedBean;

@Named
@FacesConfig
public class BackingBean {

    String name;
    String hello;
    
    @Inject
    BusinessBean businessBean;

    public void sayHello() {
        hello = businessBean.generateHello(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    
    public String getHello() {
        return hello;
    }
}

BusinessBean.java

import javax.ejb.Stateless;

@Stateless
public class BusinessBean {

    public String generateHello(String name) {
        return String.format("Hello, %s!", name);
    }    
}

The following shows that the project in Eclipse only has the 3 mentioned files:

The deployment itself also consists of only the 3 files mentioned (no IDE generated magic), although one extra step has been performed and that's that the .java classes have been compiled to their .class versions and have been put into a newly generated directory WEB-INF/classes:

Note the use of a couple of conventions that make this all work:

  • The context root is by default the name of the directory in which the app is deployed (technically: the exploded war name).
  • JSF by default maps the JSF controller servlet to *.jsf (and to /faces/* and *.faces).
  • Facelets files have a default suffix of .xhtml.
  • The backing bean's default name in EL is the simple class name with the first letter de-capitalized.
  • The backing bean is by default in request scope.
  • The bi-directional binding from the view (page.xhtml) to the model via the EL expression #{backingBean.name} takes advantage of the JavaBean naming conventions for getters/setters.
  • The EJB is by default pooled and transactional.
  • A no-interface view is created for the EJB by default (since it doesn't implement business interfaces).

Everything that is defaulted can be configured differently as needed. For instance, the default name in EL for the backing bean can be set to a different name via an attribute on the ManagedBean annotation, and the EJB can be made not transactional via an extra annotation. Some things would require XML to be configured differently. For instance, alternative mappings for the Faces Servlet or the default Facelets file suffix have to be configured in a web.xml file.

Finally, note that the goal of this example is to demonstrate one of the simplest possible setups and doesn't necessarily adheres to all best practices. In reality, for non-trivial applications you'd want to declare you instance variables as private, definitely would not use the default package for your classes, probably create separate packages for your backing and business code, make sure *.xhtml is not directly accessible (e.g. by mapping the Faces Servlet directly to .xhtml in web.xml), and if your application really grows you might want to consider putting the business code in a separate module, add interfaces to the beans, etc etc.

But the point is that Java EE (and various other Java frameworks as well), now allow you to start with very simple defaults, making the barrier to enter much lower than before. You can then refactor and configure when the need arrises.

Arjan Tijms

Sunday, July 3, 2011

Stateless vs Stateful JSF view parameters

JSF defines the concept of view parameters, which are used to support URL parameters in GET requests (although it can be used for non-faces POST parameters as well).

View parameters are defined on a Facelet with the help of the f:viewParam tag. A typical usage looks like this:

<html xmlns="http://www.w3.org/1999/xhtml"
     xmlns:h="http://java.sun.com/jsf/html"
     xmlns:f="http://java.sun.com/jsf/core"
 >
    <f:metadata>
        <f:viewParam name="foo_id" value="#{myBean.fooId}" />
    </f:metadata>

    <h:body>    
        #{myBean.fooId}
    </h:body>
</html>

In this case myBean could look like this:

@Named
@ViewScoped
public class MyBean {
    private Long fooId;

    public Long getFooId() {
        return fooId;
    }

    public void setFooId(Long fooId) {
        this.fooId = fooId;
    }
}

There's nothing really fancy going on here. When a GET request like localhost:8080/mypage?fooId=1 is processed, setFooId() is called, and when the page is rendered getFooId() is called. When we fire a GET request without the URL parameter, the setter will not be called. So, it looks like the presence of the URL parameter is what triggers the setter.

But what happens after we do a postback from that page? E.g. when we add the following to the Facelet:

<h:form>
    <h:commandButton value="do action" action="#{myBean.doAction"}"/>
</h:form>

and the following to the bean:

public void doAction() {
}

There will be no URL parameter present in the request after the postback, so it would seem logical the setter will not be called.

As it appears however, the setter will be called. What happens is that f:viewParam (UIViewParameter) is a stateful component. When it initially retrieves the URL parameter foo_id, it internally stores this in its view state. After the postback, the value is processed again and then also pushed into the model again (the backing bean). This is a direct consequence of the fact that in JSF a view is normally stateful and this behavior is actually consistent with how other UIInput components (like e.g. h:inputText) work. In case a backing bean is request scoped, this can also be really convenient as otherwise the initial URL parameter would be 'lost' after the first postback. See e.g. JSF 2.0: View parameters, where the author seems really happy with this behavior:

The UIViewParameter component also stores its value in the state, so that the value will also be available on the next postback request (most likely a clicked button or link). So you only need to provide your view parameter(s) once and not on every request.

Unfortunately, there are a couple of situations where a stateful f:viewParam can be a real nuisance. In the example given above the backing bean is already view scoped and takes care of managing its own state. Calling the setter again is simply redundant, but doesn't hurt much. Even if the backing bean loads data from a DB based on this parameter, it probably does so in the preRenderView event handler with a guard that checks if the request is not a postback:

public void onPreRenderView() {
    if (!FacesContext.getCurrentInstance().isPostback()) {
        foo = fooDao.getByID(fooId);
    }
}

However, things get a little bit problematic when taking advantage of one of the killer features of view parameters: the ability to attach converters and validators to them. Instead of letting the backing bean load the Foo instance, we can use a universal converter for this and while at it validate right away that the foo_id is legal to be used by the current user (thus preventing parameter twiddling attacks). The code would then look like this:

<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
 >
    <f:metadata>
        <f:viewParam name="foo_id" label="foo_id" value="#{myBean.foo}" converter="fooConverter" validator="fooOwnerValidator"  />
    </f:metadata>

    <h:body>    
        #{myBean.foo.id}

        <h:form>
            <h:commandButton value="do action" action="#{myBean.doAction"}"/>
        </h:form>
    </h:body>
</html>

and

@ViewScoped
@ManagedBean
public class MyBean {
    private Foo foo;

    public Foo getFoo() {
        return foo;
    }

    public void setFoo(Foo foo) {
        this.foo = foo;
    }

    public void doAction() {
    }
}

With f:viewParam being stateful, it will now do the conversion and validation on each and every postback. This is not only unnecessary (as the correct Foo instance is already safely kept in the view scoped MyBean), but it's also a needless drain on system resources and a potential slow down for this view as it may involve a DB query for each and every postback. So what we need for this particular usecase is an f:viewParam variant that doesn't do this needless converting every time. There are a few options:

  1. Create a stateless version
  2. Only do conversion and model updates when value changes (suggested by my co-worker Bauke Scholtz)
  3. Also put converted value in state, always update model, reconvert when original changes

For this article I looked at the first option, as it seemed to be the easiest one to implement. The original UIViewParameter handles its state via the following methods (Mojarra 2.1.1):

@Override
public String getSubmittedValue() {
    return (String) getStateHelper().get(PropertyKeys.submittedValue);
}
public void setSubmittedValue(Object submittedValue) {
    getStateHelper().put(PropertyKeys.submittedValue, submittedValue);
}

In order to make a stateless variant, I simply inherited and provided alternative implementations for these two methods:

@FacesComponent("com.my.UIStatelessViewParameter")
public class UIStatelessViewParameter extends UIViewParameter {

    private String submittedValue;
 
    @Override
    public void setSubmittedValue(Object submittedValue) { 
        this.submittedValue = (String)submittedValue;
    }
 
    @Override
    public String getSubmittedValue() { 
        return submittedValue;
    } 
}

I then created a new tag for this component in a facelet-taglib file (e.g. my-taglib.xml in META-INF in a jar):

<namespace>http://my.com/test</namespace>
<tag>
    <tag-name>viewParam</tag-name>
    <component>
        <component-type>com.my.UIStatelessViewParameter</component-type>
    </component>
</tag>

After this I can use this stateless variant on my Facelets:

<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:my="http://my.com/test"
 >
    <f:metadata>
        <my:viewParam name="foo_id" label="foo_id" value="#{myBean.foo}" converter="fooConverter" validator="fooOwnerValidator"  />
    </f:metadata>

    <h:body>    
        #{myBean.foo.id}

        <h:form>
            <h:commandButton value="do action" action="#{myBean.doAction"}"/>
        </h:form>
    </h:body>
</html>

I can now do as many postbacks as I want, but the (expensive) conversion only happens once when the URL parameter is actually in the request. Exactly as we wanted!

There are two drawbacks though. The first is the fact that automatically generating a bookmarkable link that includes the original URL parameters via the includeViewParams attribute of e.g. h:link does not work anymore. The second is that if the required attribute has been set to true, then this will now complain the value is missing on a postback. This can be resolved by adding a #{!facesContext.postback} expression to this attribute, but this is not a very elegant solution.

To solve these drawbacks I'll have to look into the method suggested by my co-worker Bauke and this might be the topic of a followup article.

Update:

A simple solution to avoid having to add the #{!facesContext.postback} at every place is to add the following method to the UIStatelessViewParameter class given above.

@Override
public boolean isRequired() {
    // The request parameter get lost on postbacks, however it's already present in the view scoped bean.
    // So we can safely skip the required validation on postbacks.
    return !FacesContext.getCurrentInstance().isPostback() && super.isRequired();
}

Thanks goes to Bauke for coming up with this ;)

Arjan Tijms