Валидаторы JSF 2 не могут использовать «var» из dataTable - PullRequest
1 голос
/ 03 января 2011

Мы недавно обновили наши системы с JSF 1.2 до JSF 2.0 и в настоящее время работаем над тем, чтобы все работало. Однако у нас возникают проблемы с валидаторами, когда они используются внутри таблиц данных или аналогичных компонентов. По сути, проблема в том, что валидатор не может использовать переменную, установленную таблицей данных.

Вот пример:

валидатор:

package test;

import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("test.TestValidator")
public class TestValidator implements Validator {

    private Integer length;

    public TestValidator() {
        super();
    }

    @Override
    public void validate(FacesContext context,
            UIComponent component, Object value) throws ValidatorException {

        String text = (String) value;
        if (text == null || text.trim().length() == 0) {
            return;
        }

        if (length != null && text != null && length.intValue() < text.length()) {
            String message = "The text is too long. It was " + text.length() +
                    ", but only " + length + " characters are allowed.";
            FacesMessage fm = new FacesMessage(
                    FacesMessage.SEVERITY_ERROR, message, null);
            throw new ValidatorException(fm);
        }
    }

    public Integer getLength() {
        return length;
    }

    public void setLength(Integer length) {
        this.length = length;
    }
}

TagLib:

<?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://industry-supply.dk/test</namespace>
        <tag>
            <tag-name>testValidator</tag-name>
            <validator>
                <validator-id>test.TestValidator</validator-id>
            </validator>
            <attribute>
                <name>length</name>
                <required>true</required>
                <type>java.lang.Integer</type>
            </attribute>
        </tag>
    </facelet-taglib>

Управляемый боб:

package test;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean(name = "testBean")
@RequestScoped
public class TestBean {

    public TestBean() {
    }

    public String[] getKey() {
        return new String[]{
                    "0",
                    "1",
                    "2",
                    "3"
                };
    }

    public String[] getValue() {
        return new String[]{
                    "This is a text and it's too long.",
                    "This is a text and it's too long.",
                    "This is a text and it's too long.",
                    "This is a text and it's too long."
                };
    }
}

JSF:

<?xml version='1.0' encoding='UTF-8' ?>
<!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:test="http://industry-supply.dk/test">
    <h:head>
        <title>Facelet Title</title>
    </h:head>
    <h:body>
        <h:form>
            <h:dataTable value="#{testBean.key}" var="k">
                <h:column>
                    <h:message for="val"/>
                    <h:inputText id="val" value="#{testBean.value[k]}">
                        <test:testValidator length="#{testBean.key[k]}"/>
                    </h:inputText>
                </h:column>
            </h:dataTable>
            <h:commandButton value="Submit"/>
        </h:form>
    </h:body>
</html>

При запуске проекта отображаются 4 поля ввода и командная кнопка. Каждое поле ввода содержит текст длиной 33 символа. Когда вы нажимаете «отправить», появляется сообщение об ошибке «Текст слишком длинный. Это было 33, но допускается только 0 символов». отображается для каждой строки / поля. Это неправильно, потому что "test: testValidator length =" # {testBean.key [k]} "" задает длину до 0 для первой строки, 1 для второй строки, 2 для третьей строки и 3 для четвертой строки. Поэтому для последней строки в сообщении об ошибке должно было быть сказано: «Текст слишком длинный. Это было 33, но допускается только 3 символа».

Проблема в том, что валидатор, похоже, не имеет доступа к переменной k из компонента dataTable в файле JSF. Это работало в JSF 1.2, но мы не можем заставить его работать в JSF 2.0. Мы потратили несколько дней на решение этой проблемы и действительно нуждаемся в помощи. У кого-нибудь есть идеи?

Ответы [ 2 ]

1 голос
/ 04 января 2011

Хорошо, похоже, все работает сейчас. Я создал собственный ValidatorHandler, как это было предложено Макдауэллом. Вот мои изменения:

TagLib:

<handler-class>test.CustomValidatorHandler</handler-class>

валидатор:

package test;

import javax.el.ValueExpression;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.FacesValidator;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;

@FacesValidator("test.TestValidator")
public class TestValidator implements Validator {

    public TestValidator() {
        super();
    }

    @Override
    public void validate(FacesContext context,
            UIComponent component, Object value) throws ValidatorException {

        String text = (String) value;
        if (text == null || text.trim().length() == 0) {
            return;
        }

        Integer length = getLengthValue();

        if (length != null && text != null && length.intValue() < text.length()) {
            String message = "The text is too long. It was " + text.length() +
                    ", but only " + length + " characters are allowed.";
            FacesMessage fm = new FacesMessage(
                    FacesMessage.SEVERITY_ERROR, message, null);
            throw new ValidatorException(fm);
        }
    }

    private ValueExpression lengthExpression;

    public ValueExpression getLength() {
        return lengthExpression;
    }

    public void setLength(ValueExpression length) {
        this.lengthExpression = length;
    }

    public Integer getLengthValue() {
        Integer length = null;
        if (lengthExpression != null) {
            length = (Integer) lengthExpression.getValue(
                    FacesContext.getCurrentInstance().getELContext());
        }
        return length;
    }
}

VALIDATOR HANDLER:

package test;

import javax.el.ValueExpression;
import javax.faces.context.FacesContext;
import javax.faces.view.facelets.FaceletContext;
import javax.faces.view.facelets.ValidatorConfig;
import javax.faces.view.facelets.ValidatorHandler;

public class CustomValidatorHandler extends ValidatorHandler {

    private ValueExpression lengthExpression;

    public CustomValidatorHandler(ValidatorConfig config) {
        super(config);
        FacesContext facesContext = FacesContext.getCurrentInstance();
        FaceletContext faceletContext = (FaceletContext) facesContext.getAttributes().get(FaceletContext.FACELET_CONTEXT_KEY);
        lengthExpression = config.getTag().getAttributes().get("length").getValueExpression(faceletContext, Integer.class);
    }

    @Override
    public void setAttributes(FaceletContext ctx, Object instance) {
//        super.setAttributes(ctx, instance);
        if (instance instanceof TestValidator) {
            TestValidator validator = (TestValidator) instance;
            validator.setLength(lengthExpression);
        }
    }
}
0 голосов
/ 03 января 2011

Я полагаю, что ваш валидатор содержит ошибку и вам просто повезло в предыдущих реализациях.

Из документации :

... если класс Validator хочет, чтобы значения свойств конфигурации были сохранены и восстановлены в представлении, реализация также должна реализовать StateHolder.

Когда представление восстанавливается во время операции POST, состояние длины может больше не присутствовать.

Я не помню, что происходит с ValueExpressions на валидаторах - в отличие от компонентов, валидаторы, как правило, не имеют привязывающих карт для их хранения. Возможно, вам придется создать собственный ValidatorHandler или что-то - я не рассматривал эту часть API подробно.

...