Wednesday, December 24, 2014

JSF Hacks for Advent

1. Validator with error message in user selected languages



The trick is to set the language  preference selected by user in session map, then in the validator class get the value of language preference and return respective error message in respective language.

Download full sample here.

実装は簡単なトリックです。表示言語選択をセッションマップに保存する。
入力項目バリデータロジックで選択した言語をとってそれぞれのエラー
文言をFacesMessageに設定することです。

サンプルをこちらからダウンロードしてください。(ファイル名:validator.zip)

public class NameValidator implements Validator {

    @Override
    public void validate(FacesContext context,UIComponent component,Object value)
            throws ValidatorException {
        if (component == null) {
            return;
        }
        String valueToCheck = "";
        String label = (String) component.getAttributes().get("label");
        if (value instanceof String) {
            valueToCheck = (String) escapeHtmlTextFieldValue((String) value);
            Object submittedValue = ((UIInput) component).getSubmittedValue();
            if (submittedValue != null) {
                ((UIInput) component).setSubmittedValue(value);
            } else {
                ((UIInput) component).setValue(value);
            }
        }
        if (!valueToCheck.trim().matches("^[a-zA-Z]*$")) {
            ((UIInput) component).setValid(false);
            String lang = getAttributeByName(component, "language");
            if (lang != null && lang.equals("japanese")) {
                context.addMessage(component.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR, "名前ルール間違っています、ご確認してください", "名前ルール間違っています、ご確認してください"));
            } else {
                context.addMessage(component.getClientId(context), new FacesMessage(FacesMessage.SEVERITY_ERROR, "name validation error", "Name rule is not considered, please check"));
            }
        }
    }
}



2. Using placeholder and other data attributes in JSF 2.1.


Using placeholder in JSF 2.2

JSF 2.2 allows you to use placeholder attribute using p:passthrough under xmlns="http://xmlns.jcp.org/jsf/passthrough" namespace.
Sample below.

 <html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:p="http://java.sun.com/jsf/passthrough">
    <h:form>
        <h:inputText value="#{bean.value}" p:placeholder="Enter text"/>
    </h:form>
</html>

Using placeholder in JSF 2.1

We need to tweak the textarea renderer a little to let this happen,
The steps are simple

1. Create a custom renderer extending the default TextareaRenderer

The following code allows placeholder and data-target attributes to be used with h:inputTextarea tag in JSF 2.1. More attributes can be allowed by adding them to string array "attributes".

CustomTextareaRenderer.java

package com.sample;

/* imports */

public class CustomTextareaRenderer extends TextareaRenderer {

    private static final String[] attributes = new String[]{
        "placeholder",
        "data-target"
    };

    @Override
    protected void getEndTextToRender(FacesContext context, UIComponent component, String currentValue) throws IOException {
        final ResponseWriter originalResponseWriter = context.getResponseWriter();
        context.setResponseWriter(new ResponseWriterWrapper() {

            @Override
            public ResponseWriter getWrapped() {
                return originalResponseWriter;
            }

            @Override
            public void startElement(String name, UIComponent component) throws IOException {
                super.startElement(name, component);
                if ("textarea".equalsIgnoreCase(name)) {
                    for (String attr : attributes) {
                        final String value = (String) component.getAttributes().get(attr);
                        if (value != null) {
                            super.writeAttribute(attr, value, attr);
                        }
                    }
                }
            }
        });

        super.getEndTextToRender(context, component, currentValue);
        context.setResponseWriter(originalResponseWriter);
    }
}

2. Make sure the JSF renderer kit calls to custom renderer instead of default renderer.
faces-config.xml 

<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.0"
              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-facesconfig_2_0.xsd">

    <render-kit>
        <renderer>
            <component-family>javax.faces.Input</component-family>
            <renderer-type>javax.faces.Textarea</renderer-type>
            <renderer-class>com.sample.CustomTextareaRenderer</renderer-class>
        </renderer>
    </render-kit>
</faces-config>

3. Time to play: the tag
<h:inputTextarea id="myTextArea" cols="10" rows="2" value="#{bean.value}" placeholder="Enter Text !" data-target="I use this in my javascript to custom select textareas" />

3. Using maven to validate facelets (実行直前ビルド時Faceletを自動で有効にする)



Those who are using eclipse need not worry about this because eclipse xml validator does it for you automatically.
In the pom.xml < build > section add following code

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>xml-maven-plugin</artifactId>
    <executions>
        <execution>
            <goals>
                <goal>validate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <validationSets>
            <validationSet>
                <dir>src/main/webapp</dir>
                <includes>
                    <include>**/*.xhtml</include>
                </includes>
            </validationSet>
        </validationSets>
    </configuration>
</plugin> 

1 comment :