Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JSF Custom Converter not called on null value

Tags:

java

jsf

jsf-2

I've created custom Converter for when I output java.math.BigDecimal. When the BigDecimal is 0.00 or null I want output a dash.

Here is my XHTML

<p:dataTable value="#{bean.data}" var="item">
    <p:column>
        <h:outputText value="#{item.currentValue}">
            <f:converter converterId="my.bigDecimalConverter" />
        </h:outputText>
    </p:column>
</p:dataTable>

The problem I have is when #{item.currentValue} is null the getAsString method in the Converter is not called.

@FacesConverter("my.bigDecimalConverter")
public class BigDecimalConverter implements Converter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object value) {
        if (context == null || component == null) {
            throw new NullPointerException();
        }                

        if (value == null) {
            System.out.println("null=");
            return "--";
        }

        System.out.print("Class=" + value.getClass());

        if (value instanceof String) {
            System.out.println("Str=" + value);
            return (String) value;
        }

        if (value instanceof BigDecimal) {
            BigDecimal bd = (BigDecimal)value;
            if (bd.equals(new BigDecimal("0.00"))) {
                return "--";
            } else {
                return bd.toPlainString();
            }
        }

        return "";
    }
}

I'm saying its not called because I get no errors and no println statement output when the BigDecimal is null. When the BigDecimal is not null it works as expected and "Class=class java.math.BigDecimal" gets printed out and when the BigDecimal is 0.00 I do get -- outputted on the page.

I'm using JSF 2.1, Mojarra 2.1.27

I also using the following to test my converter.

<h:outputText value="#{null}">
    <f:converter converterId="my.bigDecimalConverter" />
</h:outputText>

Reading over this question it would seem that a converter should work with a null value. https://stackoverflow.com/a/19093197/50262

like image 684
Mark Avatar asked Nov 20 '14 20:11

Mark


1 Answers

The link you posted says that a converter should work with a null but doen't say a converter will be called in every situation with null values.

Concretely it don't says a converter will be called when it is inside a h:outputText and the value is null.

If you dig in the Mojarra sources you'll see:

//Line 355 -- com.sun.faces.renderkit.html_basic.HtmlBasicRenderer
//method getCurrentValue

    Object currentObj = getValue(component);
    if (currentObj != null) {
        currentValue = getFormattedValue(context, component, currentObj);
    }

It's clear that a null value will never be converted! And I couldn't find a workaround.

Then if you really need your value to be null (you could return 0 or something) I think your only chance is making a custom renderer. It is very easy:

You write a renderer that overrides the method that matters:

package my;

import javax.faces.component.UIComponent;
import javax.faces.component.UIInput;
import javax.faces.context.FacesContext;

import com.sun.faces.renderkit.html_basic.TextRenderer;

public class HtmlCustomRenderer extends TextRenderer {

    @Override
    public String getCurrentValue(FacesContext context, UIComponent component) {

        if (component instanceof UIInput) {
            Object submittedValue = ((UIInput) component).getSubmittedValue();
            if (submittedValue != null) {
                // value may not be a String...
                return submittedValue.toString();
            }
        }

        String currentValue = null;
        Object currentObj = getValue(component);
        //Remove the 'if' to call getFormattedValue even if null
        currentValue = getFormattedValue(context, component, currentObj);
        return currentValue;

    }

}

And then we declare the renderer in faces-config.xml:

<render-kit>
    <renderer>
        <component-family>javax.faces.Output</component-family>
        <renderer-type>javax.faces.Text</renderer-type>
        <renderer-class>my.HtmlCustomRenderer</renderer-class>
    </renderer>
</render-kit>

Now your converter will be called with null values!

I hope it will help!

like image 161
fonkap Avatar answered Nov 08 '22 14:11

fonkap