Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom converter in JSF 2 with arguments

I'm trying to implement a custom truncate converter, which truncates a string at a given index and adds a continuation symbol. The converter works fine, only when i hard code the parameters, as they are not being passed to the backend. What am I doing wrong?

The parameters are properties of the converter class:

@FacesConverter(value = TruncateConverter.CONVERTER_ID)
public class TruncateConverter implements Converter, StateHolder
{
    public static final String CONVERTER_ID = "bla.blablabla.Truncate";

    private int truncateIndex;
    private String contSymbol;

Here is how i'm using the converter (or trying to):

<h:outputText id="news-text-left" value="#{newsListBean.newsList_teaser.text}">
    <f:converter converterId="bla.blablabla.Truncate" truncateIndex="150" contSymbol="..." />
</h:outputText>

I googled around for quite a bit and wasn't able to find a single example of a JSF2 converter with parameters... Thank you guys for your help, really appreciate it!

like image 381
user871784 Avatar asked Jul 23 '12 13:07

user871784


4 Answers

You may take a look at JSF2.0 sources. For example DateTimeConverter... JSF sources available here in svn reposotory: https://svn.java.net/svn/mojarra~svn/trunk

IMO creating such converter is not easy. It also required to create converter tag to register converter.

Other way to pass some data to converter is attibutes. So You can write

<h:outputText ...>
  <f:converter converterId="bla.blablabla.Truncate" />
  <f:attribute name="truncateIndex" value="150"/>
</h:outputText>

Than call to component.getAttributes().get("truncateIndex"); in converter code.

like image 191
Maks Avatar answered Nov 05 '22 23:11

Maks


Based on @Maks solution: It's possible to combine the converter and the attribute in one tag:

<facelet-taglib version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
    <namespace>http://mycompany.com/some-identifier</namespace>
    <tag>
        <tag-name>truncate</tag-name>
        <converter>
            <converter-id>bla.blablabla.Truncate</converter-id>
        </converter>
        <attribute>
            <name>truncateIndex</name>
        </attribute>
    </tag>
</facelet-taglib>

Then you can use the converter like this:

<ui:composition xmlns="http://www.w3.org/1999/xhtml"
    xmlns:my="http://mycompany.com/some-identifier">

  <my:truncate truncateIndex="150" />

</ui:composition>

You also don't need to grab the parameter from the component-attributes. A bean-property with the same name will be populated automatically:

@FacesConverter("bla.blablabla.Truncate")
public class Truncate implements Converter {

    private String truncateIndex;

    // getters + setters

    ...

}
like image 45
lefloh Avatar answered Nov 05 '22 23:11

lefloh


http://jerryorr.blogspot.nl/2011/10/creating-jsf-12-custom-converter-with.html is a good guide to set up your first custom converter with parameters

like image 4
Rob Avatar answered Nov 05 '22 21:11

Rob


This is how I did it (in a separated jar file, and using maven's default directories):

1) Create the converter's class (inside src/main/java)

2) Create a .taglib.xml class (inside src/main/resources/META-INF)

3) Create a faces-config.xml (inside src/main/resources/META-INF)

Example:

Step 1)

package com.ocabit.jsf.converter;



import java.io.Serializable;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;

import org.springframework.stereotype.Service;

import com.ocabit.utils.currency.CurrencyUtils;


/**
 * Converter para valores BigDecimal.
 * 
 * @author Carlos Eduardo Pauluk
 * 
 */
@FacesConverter("bigDecimalConverter")
@Service("bigDecimalConverter")
public class BigDecimalConverter implements Converter, Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    public static final String CONVERTER_ID = "com.ocabit.jsf.converter.BigDecimalConverter";

    /**
     * Em caso de null, força a saída para 0.0;
     */
    private boolean nullToZero = false;

    /**
     * Em caso de zero, força a saída para null;.
     */
    private boolean zeroToNull = false;

    /**
     * Só retorna números positivos.
     */
    private boolean onlyAbs = false;

    /**
     * Só retorna números negativos.
     */
    private boolean onlyNeg = false;

    /**
     * Quantidade de casas decimais.
     */
    private int decimals = 2;

    @Override
    public Object getAsObject(final FacesContext context, final UIComponent component, final String value) {
        try {
            BigDecimal bd = new BigDecimal(value);
            bd = bd.setScale(getDecimals(), RoundingMode.HALF_DOWN);

            if (bd.equals(BigDecimal.ZERO) && isZeroToNull()) {
                return null;
            }

            if (isOnlyAbs()) {
                bd = bd.abs();
            }
            if (isOnlyNeg()) {
                bd = bd.abs();
                bd = bd.negate();
            }

            return bd;
        } catch (final Exception e) {
            BigDecimal bd = null;
            if (isNullToZero()) {
                bd = CurrencyUtils.getBigDecimalCurrency("0.0");
                bd = bd.setScale(getDecimals(), RoundingMode.HALF_DOWN);
            }
            return bd;
        }
    }

    @Override
    public String getAsString(final FacesContext context, final UIComponent component, final Object value) {
        if (!(value instanceof BigDecimal)) {
            throw new ConverterException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro ao converter o valor decimal.", ""));
        }

        final NumberFormat nf = NumberFormat.getInstance();
        // sempre terá 2 casas decimais
        nf.setMinimumFractionDigits(2);
        nf.setMaximumFractionDigits(2);
        return nf.format(((BigDecimal) value).doubleValue());
    }

    public boolean isNullToZero() {
        return nullToZero;
    }

    public void setNullToZero(boolean nullToZero) {
        this.nullToZero = nullToZero;
    }

    public boolean isZeroToNull() {
        return zeroToNull;
    }

    public void setZeroToNull(boolean zeroToNull) {
        this.zeroToNull = zeroToNull;
    }

    public boolean isOnlyAbs() {
        return onlyAbs;
    }

    public void setOnlyAbs(boolean onlyAbs) {
        this.onlyAbs = onlyAbs;
    }

    public boolean isOnlyNeg() {
        return onlyNeg;
    }

    public void setOnlyNeg(boolean onlyNeg) {
        this.onlyNeg = onlyNeg;
    }

    public int getDecimals() {
        return decimals;
    }

    public void setDecimals(int decimals) {
        this.decimals = decimals;
    }

}

Step 2)

<!DOCTYPE facelet-taglib PUBLIC
    "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
    "facelet-taglib_1_0.dtd">
<facelet-taglib version="2.2"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facelettaglibrary_2_2.xsd">
    <namespace>http://ocabit.com.br/facelets</namespace>


    <tag>
        <tag-name>convertBigDecimal</tag-name>      
        <converter>
            <converter-id>com.ocabit.jsf.converter.BigDecimalConverter</converter-id>           
        </converter>    
    </tag>


</facelet-taglib>

Step 3)

<?xml version="1.0" encoding="UTF-8"?>
<faces-config xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
        http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

    <converter>
        <description></description>
        <converter-id>com.ocabit.jsf.converter.BigDecimalConverter</converter-id>
        <converter-class>com.ocabit.jsf.converter.BigDecimalConverter</converter-class>
        <property>
            <property-name>nullToZero</property-name>
            <property-class>boolean</property-class>
            <description>Ao invés de retornar 'null', retorna '0.0'</description>
        </property>
        <property>
            <property-name>zeroToNull</property-name>
            <property-class>boolean</property-class>
            <description>Ao invés de retornar '0.0', retorna 'null'</description>
        </property>
        <property>
            <property-name>onlyAbs</property-name>
            <property-class>boolean</property-class>
            <description>Somente retorna números positivos</description>
        </property>
        <property>
            <property-name>onlyNeg</property-name>
            <property-class>boolean</property-class>
            <description>Somente retorna números negativos</description>
        </property>
        <property>
            <property-name>decimals</property-name>
            <property-class>int</property-class>
            <description>Quantidade de casas decimais</description>
        </property>
    </converter>


</faces-config>

Voilà.

like image 1
chuckedw Avatar answered Nov 05 '22 23:11

chuckedw