-
1. Re: Seam custom validator
wrzep Mar 11, 2008 5:50 PM (in response to lasansue.jeremy.girard.satives.fr)
jeremy girard wrote on Mar 11, 2008 04:47 PM:
But what i don't understand, it's how to code the validator to be used as an annotation.
If someone could give me an example (as @zipcode) it would be helping me a lot.Have a look at the
Hibernate Validator documentation.Cheers,
-Pawel -
2. Re: Seam custom validator
mpopetz Mar 11, 2008 6:22 PM (in response to lasansue.jeremy.girard.satives.fr)The docs are good at the pointer he gave you. Here's one I wrote so that I can have a pattern validator that doesn't care if the value is blank.
It'd be nice if there were a central repository to share validators since they're so common? Guess I should ask that on the hibernate list...
-mp
import java.lang.annotation.Retention; import java.lang.annotation.*; import org.hibernate.validator.ValidatorClass; @ValidatorClass(OptionalPatternValidator.class) @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface OptionalPattern { /** regular expression */ String regex(); /** regular expression processing flags */ int flags() default 0; String message() default "{validator.pattern}"; }
import java.io.Serializable; import java.util.regex.Matcher; import org.hibernate.validator.Pattern; import org.hibernate.validator.PatternValidator; import org.hibernate.validator.Validator; public class OptionalPatternValidator implements Validator<OptionalPattern>, Serializable { private java.util.regex.Pattern pattern; public void initialize(OptionalPattern parameters) { pattern = java.util.regex.Pattern.compile( parameters.regex(), parameters.flags() ); } public boolean isValid(Object value) { if ( value == null ) return true; if ( !( value instanceof String ) ) return false; String string = (String) value; if(string.length() == 0) return true; Matcher m = pattern.matcher( string ); return m.matches(); } }
-
3. Re: Seam custom validator
lasansue.jeremy.girard.satives.fr Mar 11, 2008 6:31 PM (in response to lasansue.jeremy.girard.satives.fr)Thank you both for your replies.
I will try it tomorrow ...
-
4. Re: Seam custom validator
kariem Mar 12, 2008 10:35 AM (in response to lasansue.jeremy.girard.satives.fr)
It'd be nice if there were a central repository to share validators since they're so common? Guess I should ask that on the hibernate list...Marcus, if you could add the link to your post to the hibernate list here, I would be very grateful. It did not take long for me to implement a custom validator, but I think the documentation is not really sufficient, and some examples really help.
Going to share my validator here. You can use it to enforce a password policy:
@Length(min = 8, max = 20) @PasswordPolicyRestricted(minDigits = 1, minAlphas = 1) String newPassword;
Declaration:
import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; import static java.lang.annotation.ElementType.*; import static java.lang.annotation.RetentionPolicy.*; import org.hibernate.validator.ValidatorClass; @ValidatorClass(PasswordPolicyRestrictedValidator.class) @Target({FIELD, METHOD}) @Retention(RUNTIME) @Documented public @interface PasswordPolicyRestricted { /** @return minimum number of characters from a-z (lower or upper case) */ int minAlphas() default 0; /** @return minimum number of digits */ int minDigits() default 0; /** @return error message key */ String message() default "{validator.password_policy}"; }
Implementation:
import java.lang.annotation.Annotation; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.hibernate.validator.Validator; public class PasswordPolicyRestrictedValidator implements Validator<PasswordPolicyRestricted> { Pattern ALPHA = Pattern.compile("[a-zA-Z]"); Pattern DIGIT = Pattern.compile("\\d"); private PasswordPolicyRestricted policy; /** @see Validator#initialize(Annotation) */ public void initialize(PasswordPolicyRestricted passwordPolicy) { this.policy = passwordPolicy; } public boolean isValid(Object o) { if (o == null) { return false; } if (o instanceof String) { return isValid((String) o); } return isValid(o.toString()); } /** * @param password * the password to check * @return whether password is valid according to its annotation */ public boolean isValid(String password) { return check(password, policy.minAlphas(), ALPHA) && check(password, policy.minDigits(), DIGIT); } /** * @param sequence * the sequence to check * @param min * minimum number of {@code pattern} * @param pattern * the pattern to check */ private boolean check(String sequence, int min, Pattern pattern) { if (min > 0) { Matcher m = pattern.matcher(sequence); int count = 0; while (m.find()) { count++; } if (min > count) { return false; } } return true; } }
Don't forget that you can leverage the seam infrastructure for i18n (Marcus also used it in his example) by declaring the message() method in the interface. With this, you can define the message in your .properties file:
validator.password_policy=Password policy: minimum digits: {minDigits}; minimum letters: {minAlphas}
-
5. Re: Seam custom validator
lasansue.jeremy.girard.satives.fr Mar 12, 2008 1:14 PM (in response to lasansue.jeremy.girard.satives.fr)I managed to make a custom validator but there is something more.
How can you have a non null EntityManager in your validator impl ?Here is my validator.
Entity manager is always null.@Name("uniqueEntityValidator") @Stateless @JndiName(value="blog/UniqueEntityValidator/local") public class UniqueEntityValidator implements Validator<UniqueEntity>, Serializable, Test { /** * */ private static final long serialVersionUID = 1L; private String targetEntity; private String field; @In(create=true) EntityManager entityManager; public void initialize(UniqueEntity parameters) { targetEntity = parameters.targetEntity(); field = parameters.field(); } public boolean isValid(Object value) { Query query = entityManager.createQuery("From "+targetEntity+" where "+field+" = :value"); query.setParameter("value", value); try{ query.getSingleResult(); return false; }catch(final NoResultException e){ return true; } } }
I need it to perform a validation on unique constraint.
Thanks
-
6. Re: Seam custom validator
kariem Mar 12, 2008 2:14 PM (in response to lasansue.jeremy.girard.satives.fr)I think this should work the way you wrote it. Your entity manager has the name
entityManager
?Did you try method-level injection via components.xml (I am not sure if that works for session beans, though)?
Recently, I had a similar issue, but I solved it with a different approach. Nobody commented yet, so I don't really know, whether this is a feasible solution for you. You need to have the following set up for this solution to work (if it does not work with @In or method-level injection):
- Use entity home objects
- Use hibernate session
In addition, the processing occurs in invoke application (EntityHome.save() and EntityHome.update()) instead of the validation phase.
I can share the code, but as I said, nobody gave feedback and I consider it rather a hack.
-
7. Re: Seam custom validator
lasansue.jeremy.girard.satives.fr Mar 12, 2008 2:25 PM (in response to lasansue.jeremy.girard.satives.fr)Yes my entitymanager is named entitymanager.
I haven't tried by component.xml.
I think i gonna do this in a regular seam component (registerAction) -
8. Re: Seam custom validator
mars1412 Mar 12, 2008 3:23 PM (in response to lasansue.jeremy.girard.satives.fr)shouldn't you use @PersistenceContext in EJBs?
-
9. Re: Seam custom validator
lasansue.jeremy.girard.satives.fr Mar 12, 2008 5:25 PM (in response to lasansue.jeremy.girard.satives.fr)I tried, but don't work -> null ...
-
10. Re: Seam custom validator
fernando_jmt Mar 12, 2008 8:25 PM (in response to lasansue.jeremy.girard.satives.fr)Have you tried something like?:
@Name("uniqueEntityValidator") @Stateless @JndiName(value="blog/UniqueEntityValidator/local") public class UniqueEntityValidator implements Validator<UniqueEntity>, Serializable, Test { /** * */ private static final long serialVersionUID = 1L; private String targetEntity; private String field; public void initialize(UniqueEntity parameters) { targetEntity = parameters.targetEntity(); field = parameters.field(); } public boolean isValid(Object value) { Query query = ((EntityManager) Component.getInstance("entityManager")).createQuery("From "+targetEntity+" where "+field+" = :value"); query.setParameter("value", value); try{ query.getSingleResult(); return false; }catch(final NoResultException e){ return true; } } }
-
11. Re: Seam custom validator
lasansue.jeremy.girard.satives.fr Mar 13, 2008 11:38 AM (in response to lasansue.jeremy.girard.satives.fr)I tried, null !
But it works fine with a business validation instead of hibernate validation -
12. Re: Seam custom validator
sambp Oct 20, 2009 1:21 PM (in response to lasansue.jeremy.girard.satives.fr)I'm having the same problem. I'm using a Hibernate Session, and he's always null. But it works fine with a business validation too. Someone fix that? Sorry my English.
-
13. Re: Seam custom validator
sambp Oct 31, 2009 8:29 PM (in response to lasansue.jeremy.girard.satives.fr)I solve the @In problem using:
Session session = (Session) Component.getInstance("session");
But now when I try to saveOrUpdate I got another exception:
java.lang.reflect.InvocationTargetException javax.faces.el.EvaluationException: java.lang.reflect.InvocationTargetException at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:91) at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:91) at javax.faces.component.UICommand.broadcast(UICommand.java:383) at org.ajax4jsf.component.AjaxActionComponent.broadcast(AjaxActionComponent.java:55) at org.ajax4jsf.component.AjaxViewRoot.processEvents(AjaxViewRoot.java:321) at org.ajax4jsf.component.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:296) at org.ajax4jsf.component.AjaxViewRoot.processPhase(AjaxViewRoot.java:253) at org.ajax4jsf.component.AjaxViewRoot.processApplication(AjaxViewRoot.java:466) at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:97) at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:251) at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:117) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:244) at org.apache.catalina.core.ApplicationFilterChain.servletService(ApplicationFilterChain.java:427) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:333) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83) at org.jboss.seam.web.IdentityFilter.doFilter(IdentityFilter.java:40) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.MultipartFilter.doFilter(MultipartFilter.java:90) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.ExceptionFilter.doFilter(ExceptionFilter.java:64) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.web.RedirectFilter.doFilter(RedirectFilter.java:45) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.ajax4jsf.webapp.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:178) at org.ajax4jsf.webapp.BaseFilter.handleRequest(BaseFilter.java:290) at org.ajax4jsf.webapp.BaseFilter.processUploadsAndHandleRequest(BaseFilter.java:390) at org.ajax4jsf.webapp.BaseFilter.doFilter(BaseFilter.java:517) at org.jboss.seam.web.Ajax4jsfFilter.doFilter(Ajax4jsfFilter.java:56) at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:69) at org.jboss.seam.servlet.SeamFilter.doFilter(SeamFilter.java:158) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:246) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:214) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:313) at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:287) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:218) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:94) at com.sun.enterprise.web.PESessionLockingStandardPipeline.invoke(PESessionLockingStandardPipeline.java:98) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:222) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:166) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:648) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:593) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:587) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1096) at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:288) at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:647) at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:579) at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:831) at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341) at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263) at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214) at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265) at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.seam.util.Reflections.invoke(Reflections.java:22) at org.jboss.seam.intercept.RootInvocationContext.proceed(RootInvocationContext.java:32) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:56) at org.jboss.seam.transaction.RollbackInterceptor.aroundInvoke(RollbackInterceptor.java:28) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) at org.jboss.seam.core.BijectionInterceptor.aroundInvoke(BijectionInterceptor.java:77) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) at org.jboss.seam.core.MethodContextInterceptor.aroundInvoke(MethodContextInterceptor.java:44) at org.jboss.seam.intercept.SeamInvocationContext.proceed(SeamInvocationContext.java:68) at org.jboss.seam.intercept.RootInterceptor.invoke(RootInterceptor.java:107) at org.jboss.seam.intercept.JavaBeanInterceptor.interceptInvocation(JavaBeanInterceptor.java:185) at org.jboss.seam.intercept.JavaBeanInterceptor.invoke(JavaBeanInterceptor.java:103) at fachada.VerbeteAction_$$_javassist_seam_3.salvarVerbete(VerbeteAction_$$_javassist_seam_3.java) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:335) at org.jboss.el.util.ReflectionUtil.invokeMethod(ReflectionUtil.java:348) at org.jboss.el.parser.AstPropertySuffix.invoke(AstPropertySuffix.java:58) at org.jboss.el.parser.AstValue.invoke(AstValue.java:96) at org.jboss.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) at com.sun.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:68) at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:77) ... 58 more Caused by: java.lang.StackOverflowError at org.jboss.seam.contexts.Contexts.isMethodContextActive(Contexts.java:89) at org.jboss.seam.contexts.Contexts.lookupInStatefulContexts(Contexts.java:157) at org.jboss.seam.Component.getInstance(Component.java:1982) at org.jboss.seam.Component.getInstance(Component.java:1977) at org.jboss.seam.Component.getInstance(Component.java:1972) at validacao.palavra.ValidadorPalavraUnica.isValid(ValidadorPalavraUnica.java:39) at validacao.palavra.ValidadorPalavraUnica.isValid(ValidadorPalavraUnica.java:32) ......etc