You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@myfaces.apache.org by Barry Kaplan <gr...@memelet.com> on 2006/03/13 17:39:00 UTC

hibernate validator PhaseListener

A few days there was a thread on using Hibernate Validator. Here is a 
quick prototype. I've only played with a tiny bit, so I'm sure there are 
issues:

-barry

----

package org.opentrader.infra.jsf.validation;

import java.util.Collection;
import java.util.Map;

import javax.faces.application.FacesMessage;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.faces.event.PhaseListener;

import org.hibernate.validator.InvalidValue;
import org.opentrader.infra.validation.BeanValidator;
import org.opentrader.infra.validation.ValidatedBean;
import org.springframework.context.ApplicationContext;
import org.springframework.web.jsf.WebApplicationContextVariableResolver;

// TODO Test and harden this spike.
public class HibernateValidatorPhaseListener implements PhaseListener {

    private BeanValidator beanValidator;
   
    public PhaseId getPhaseId() {
        return PhaseId.PROCESS_VALIDATIONS;
    }
   
    public void beforePhase(PhaseEvent arg0) {
        //empty
    }

    public void afterPhase(PhaseEvent event) {
        FacesContext facesContext = event.getFacesContext();
        ExternalContext externalContext = facesContext.getExternalContext();
        BeanValidator validator = getValidator(externalContext);
        processValidators(externalContext.getRequestMap(), facesContext, 
validator);
        processValidators(externalContext.getSessionMap(), facesContext, 
validator);
    }
   
    @SuppressWarnings("unchecked")
    private BeanValidator getValidator(ExternalContext externalContext) {
        if (beanValidator == null) {
            ApplicationContext context = (ApplicationContext) 
externalContext.getApplicationMap().get(
                    
WebApplicationContextVariableResolver.WEB_APPLICATION_CONTEXT_VARIABLE_NAME);
            Map<String, BeanValidator> beans = 
context.getBeansOfType(BeanValidator.class);
            if (beans.size() == 0) {
                throw new IllegalStateException("Bean of class 
BeanValidator not found in application-context");
            }
            if (beans.size() == 0) {
                throw new IllegalStateException("More than one bean of 
class BeanValidator found in application-context: beans=" + beans.keySet());
            }
            beanValidator = beans.values().iterator().next();
        }
        return beanValidator;
    }

    private void processValidators(Map scope, FacesContext facesContext, 
BeanValidator validator) {
        Collection collection = scope.values();
        for (Object object : collection) {
            if 
(object.getClass().isAnnotationPresent(ValidatedBean.class)) {
                InvalidValue[] invalidValues = 
validator.validateBean(object);
                if (invalidValues.length > 0) {
                    addFacesMessages(invalidValues, facesContext);
                }
            }
        }
    }

    private void addFacesMessages(InvalidValue[] invalidValues, 
FacesContext facesContext) {
        for (InvalidValue invalidValue : invalidValues) {
            FacesMessage message = new FacesMessage();
            message.setSeverity(FacesMessage.SEVERITY_ERROR);
            message.setSummary(invalidValue.toString());
            message.setDetail(invalidValue.toString());
            facesContext.addMessage(null, message);
        }
    }

}



Re: hibernate validator PhaseListener

Posted by Barry Kaplan <gr...@memelet.com>.
Adam Winer wrote:
> Definitely a very interesting approach;  one problem is that it'll
> validate too much.  For example, it'll validate beans that aren't
> even used on the current page.  It'll also validate beans that
> aren't yet valid because they're being created and populated
> over multiple pages, and beans that weren't set on this request
> because they're in a different form (or subform) than the one
> that was submitted.
>   

Yes, these are real problems. One of the things I was toying with 
extending hibernate validator (or wrapping spring-validator or 
commons-validator to use an annotation based approach) and adding a 
context property that indicates which properties should validated when.

Hibernate validator will also set database schema constraints, I want to 
keep that. But that feature is enabled by a marker interface on the 
validator, so if the wrapper approach supports that marker interface it 
may work out ok.

But the validator I posted was just an experiment. There are lots of 
issues still to work out. Especially how to get a single validation 
specification that is used at the db-level, app-level, and jsf-level, 
and javascript-level (when appropriate of course).

> The interesting question is how to tie an annotation
> driven approach like this - which I really like - to all of
> the information resident in the UIComponent tree.
>   

Yes. Any ideas?

-bk

Re: hibernate validator PhaseListener

Posted by Adam Winer <aw...@gmail.com>.
Definitely a very interesting approach;  one problem is that it'll
validate too much.  For example, it'll validate beans that aren't
even used on the current page.  It'll also validate beans that
aren't yet valid because they're being created and populated
over multiple pages, and beans that weren't set on this request
because they're in a different form (or subform) than the one
that was submitted.

The interesting question is how to tie an annotation
driven approach like this - which I really like - to all of
the information resident in the UIComponent tree.

-- Adam



On 3/13/06, Barry Kaplan <gr...@memelet.com> wrote:
> A few days there was a thread on using Hibernate Validator. Here is a
> quick prototype. I've only played with a tiny bit, so I'm sure there are
> issues:
>
> -barry
>
> ----
>
> package org.opentrader.infra.jsf.validation;
>
> import java.util.Collection;
> import java.util.Map;
>
> import javax.faces.application.FacesMessage;
> import javax.faces.context.ExternalContext;
> import javax.faces.context.FacesContext;
> import javax.faces.event.PhaseEvent;
> import javax.faces.event.PhaseId;
> import javax.faces.event.PhaseListener;
>
> import org.hibernate.validator.InvalidValue;
> import org.opentrader.infra.validation.BeanValidator;
> import org.opentrader.infra.validation.ValidatedBean;
> import org.springframework.context.ApplicationContext;
> import org.springframework.web.jsf.WebApplicationContextVariableResolver;
>
> // TODO Test and harden this spike.
> public class HibernateValidatorPhaseListener implements PhaseListener {
>
>     private BeanValidator beanValidator;
>
>     public PhaseId getPhaseId() {
>         return PhaseId.PROCESS_VALIDATIONS;
>     }
>
>     public void beforePhase(PhaseEvent arg0) {
>         //empty
>     }
>
>     public void afterPhase(PhaseEvent event) {
>         FacesContext facesContext = event.getFacesContext();
>         ExternalContext externalContext = facesContext.getExternalContext();
>         BeanValidator validator = getValidator(externalContext);
>         processValidators(externalContext.getRequestMap(), facesContext,
> validator);
>         processValidators(externalContext.getSessionMap(), facesContext,
> validator);
>     }
>
>     @SuppressWarnings("unchecked")
>     private BeanValidator getValidator(ExternalContext externalContext) {
>         if (beanValidator == null) {
>             ApplicationContext context = (ApplicationContext)
> externalContext.getApplicationMap().get(
>
> WebApplicationContextVariableResolver.WEB_APPLICATION_CONTEXT_VARIABLE_NAME);
>             Map<String, BeanValidator> beans =
> context.getBeansOfType(BeanValidator.class);
>             if (beans.size() == 0) {
>                 throw new IllegalStateException("Bean of class
> BeanValidator not found in application-context");
>             }
>             if (beans.size() == 0) {
>                 throw new IllegalStateException("More than one bean of
> class BeanValidator found in application-context: beans=" + beans.keySet());
>             }
>             beanValidator = beans.values().iterator().next();
>         }
>         return beanValidator;
>     }
>
>     private void processValidators(Map scope, FacesContext facesContext,
> BeanValidator validator) {
>         Collection collection = scope.values();
>         for (Object object : collection) {
>             if
> (object.getClass().isAnnotationPresent(ValidatedBean.class)) {
>                 InvalidValue[] invalidValues =
> validator.validateBean(object);
>                 if (invalidValues.length > 0) {
>                     addFacesMessages(invalidValues, facesContext);
>                 }
>             }
>         }
>     }
>
>     private void addFacesMessages(InvalidValue[] invalidValues,
> FacesContext facesContext) {
>         for (InvalidValue invalidValue : invalidValues) {
>             FacesMessage message = new FacesMessage();
>             message.setSeverity(FacesMessage.SEVERITY_ERROR);
>             message.setSummary(invalidValue.toString());
>             message.setDetail(invalidValue.toString());
>             facesContext.addMessage(null, message);
>         }
>     }
>
> }
>
>
>