24 Jun

static version of getClass()

It is very easy to get the current class if you have an instance of it just by instance.getClass(), but what if you are inside a static method and you have no instance? After I spent some time thinking about this problem, I came up with the following solution:

public static Class<?> getClassStatic()
{
    // get the current thread's stacktrace
    StackTraceElement[] stacktrace
        = Thread.currentThread().getStackTrace();

    // get the class name of the calling method's class
    // 2, because 0 is getStackTrace() and 1 is getClassStatic()
    String className = stacktrace[2].getClassName();

    try
    {
        // get the class instance for the given class name
        return Class.forName(className);
    }
    catch (ClassNotFoundException e)
    {
        // will never be the case, but ClassNotFoundException
        // is checked, thus we have to catch it.
        return null;
    }
}

This solution uses the current Thread’s stacktrace to get the class name of the current class and afterwards it uses Class.forName(…) to get the instance of the class. Not very beautiful, but it works.

03 Jun

Validation errors and bean updates

One problem some people are facing in JSF is that a user inputs invalid data to a form which causes the related validators (or also converters) to fail and thus setting the valid property on every affected input component to false. This has the effect that those components will store this invalid value as a local value, which will also be rendered. This means that the component will not show the actual value from the managed bean, but the local value from its own state.

If the user now decides to change the values in the managed bean by some action in another form (or just by an AJAX request), the components won’t display the new values from the bean but their old local values. This problem actually causes some people to not use the JSF standard converters and validators, but to use their own ones in the related action methods.

To circumvent this problem the valid property as well as the local and the submitted value have to be reset on every affected input component. In JSF 1.2 the method resetValue() was introduced to achieve this in a convenient way. However if you’re using JSF 1.1, you will have to implement this yourself.

public void resetValue()
{
    setSubmittedValue(null);
    setValue(null);
    setLocalValueSet(false);
    setValid(true);
}

The fact that you will have to call this method before rendering on every input component which (maybe) has an invalid value and whose value has changed in the managed bean is kinda annoying. The best way to achieve this is to traverse the component tree either at the end of the action method which changes the value(s) in the bean or in a PhaseListener that will be called before the rendering occurs.

An example

Imagine you have the following facelet page:

<!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:f="http://java.sun.com/jsf/core"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head>
    <title>JSF - validation errors and bean updates</title>
</h:head>
<h:body>
    <h:form id="form1">
        <h:messages id="messages" />

        <h:inputText id="input" value="#{myBean.input}">
            <f:validateLength minimum="5" />
        </h:inputText>

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

    <h:form id="form2">
        <h:commandButton value="change input value"
                action="#{myBean.changeInput}" />
    </h:form>

    <ui:debug />
</h:body>
</html>

and the following managed bean:

@ManagedBean(name = "myBean")
@SessionScoped
public class MyBean
{

    private String input;

    public String getInput()
    {
        return input;
    }

    public void setInput(String input)
    {
        this.input = input;
    }

    public String action()
    {
        // process the valid user input

        return null;
    }

    public String changeInput()
    {
        // change input
        input = "changed input";

        return null;
    }

}

Now open the page in the browser, input for example “12″ into the text field (which is shorter than the minimum length) and click “Submit”. You will then get a validation error saying the inputted value is too short. If you now click the “change input value” button, the value in the managed bean will be changed, but the input field will still display “12″ from before. If you want the input field to display “changed input”, you will have to do the following on changeInput():

public String changeInput()
{
    // change input
    input = "changed input";

    // reset the input field
    UIInput field = (UIInput) FacesContext.getCurrentInstance()
            .getViewRoot().findComponent("form1:input");
    field.resetValue();

    return null;
}

Now the input field will display “changed input”. Of course this could also happen in a PhaseListener on before render view.

The problem with this solution is that all fields will have to have static Ids or will have to be bound to the bean using the binding attribute (not recommended) and furthermore this could end up in quite a lot of code, if you have lots of input components in the form. If you are using JSF 2.0, you can simplify this solution by using the tree visiting API (javax.faces.component.visit), however it rather seems like a workaround than a real solution.

Better solutions?

One solution would be to have a method on UIForm (or even on FacesContext?) saying resetValues(), which itself traverses the form’s children to reset all EditableValueHolders.

Another idea is to have a resetOnModelValueUpdate attribute on every input component which can be set to true or false. If it is set to true, the component will store the current version of the value from the managed bean in its state and check on the next postback for changes. If the value in the managed bean was changed by any other component or action, the component will automatically reset itself and use the new value from the bean.

Maybe something of this will make it in the JSF 2.1 spec. We’ll see!