1 2 Previous Next 15 Replies Latest reply on Mar 4, 2011 1:23 AM by Nicklas Karlsson

    How to trigger custom annotated date validator.

    Sam W Expert

      Hi,

       

      With jsf2.0, the xhtml webpage I have written contains the following items:

      1. date field

      2. a submit button

       

       

      I have written a custom date annotation validation (based on special business rules) class.

      When the submit button is clicked, I would expect it will trigger the custom date validator first, if date is valid, it will popup a simple dialog.

       

      The problem is when I click the submit button, there is no trace go into the validator class before popup the dialog.

       

      here is the portion of xhtml code:

       

       

      <p:dateSelector id="consentDate" label="Patient withdrawal consent date" mandatory="true" value="#{patientSearchController.bean.consentDate}"/>

      <div class="submitButtons">

      <h:panelGroup  rendered="#{patientSearchController.showWithdrawal}">

      <h:commandButton actionListener="#{patientSearchController.consentDateWithdrawal}" value="Submit Withdrawal">

      <f:attribute name="patient" value="#{patient}" />

      </h:commandButton>

      </h:panelGroup>

         </div>

         <p:popup controller="#{patientSearchController}" />

       

      Annotated vadliation:

       

      @PatientSearchBeanValid()

       

      public class PatientSearchPageBean implements IBaseBean{

       

      private static final String CONSENT_DATE_FIELD = "Withdrawal consent date";

       

      @WithdrawalConsentDateString(field=CONSENT_DATE_FIELD)

      private String consentDate;

       

       

      WithdrawalConsentDateString class:

       

      @Documented

      @Inherited

      @Retention(RetentionPolicy.RUNTIME)

      @Target( { ElementType.TYPE, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.METHOD,

      ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE, ElementType.PARAMETER })

      @Constraint(validatedBy = WithdrawalConsentDateStringValidator.class)

      @DateString

      public @interface WithdrawalConsentDateString {

      public static final String CONSENT_DATE_IN_FUTURE = "ConsentDateInFuture";

       

      String message() default "";

       

      Class<?>[] groups() default {};

       

      Class<? extends Payload>[] payload() default {};

       

      String field() default "";

      }

       

       

      WithdrawalConsentDateStringValidator class:

       

       

      public class WithdrawalConsentDateStringValidator implements ConstraintValidator<WithdrawalConsentDateString, String> {

       

      private String fieldName;

       

      @Override

      public void initialize(WithdrawalConsentDateString arg0) {

      fieldName = arg0.field();

      System.out.println(" ========== WithdrawalConsentDateStringValidator 000==========");

      }

       

      @Override

      public boolean isValid(String dateStr, ConstraintValidatorContext context) {

      boolean valid = true;

      System.out.println(" ========== WithdrawalConsentDateStringValidator ==========");

      List<String> errorMsgs = DateStringValidator.validateDateString(dateStr, fieldName);

      if(CollectionUtils.isNotEmpty(errorMsgs)){

      valid = false;

      for (String errMsg : errorMsgs) {

      ValidatorUtils.addMessage(context,errMsg);

      }

      }

       

      Date consentDate = DateUtils.convertStringToDate(dateStr);

       

      if (!StringUtils.isEmpty(dateStr)) {

      if (consentDate != null) {

      // Must in the past

      Date today = DateUtils.getCurrentDate();

      if (DateUtils.afterDay(consentDate, today)) {

      ValidatorUtils.addMessage(context, WithdrawalConsentDateString.CONSENT_DATE_IN_FUTURE);

      valid = false;

      }

      }

      }

      return valid;

      }

      }

       

       

      When the submit button is clickec, I don't see the Sytem.out prints out from the console.

       

      I suspect the vaildator is never get called.

      Is there anything wrong with my validation code setup?

       

      Thanks a lot

      Sam

        • 1. How to trigger custom annotated date validator.
          Nicklas Karlsson Master

          How do you register the validator?

          • 2. How to trigger custom annotated date validator.
            Sam W Expert

            Hello

             

            I through the annotation @WithdrawalConsentDateString on top of the member variable name would make this validation call automatically?

             

            Sorry I am still a newbie in annotation validation.

             

            Let me know how I register this annotated validator.

            I have searched .xml configuration file, there s nothing there.

             

            Thanks

            Sam

            • 4. How to trigger custom annotated date validator.
              Benjamin Seyinbour Expert

              Hi,

               

              I have never tried annotating a validator before, but here is what I would do:

               

               

              You could use the commandButton actionListener to trigger event and proceess validation but it is not a validator. Here is an example of a validator:

               

              In JSF:

               

              <f:validator validatorId="WithdrawalConsentDateStringValidator"/>

               

              As Nicklas have already mentioned, you then need to register your validator in faces-config.xml as follows:

               

              <validator>

              <display-name>WithdrawalConsentDate StringValidator</display-name>

                 <validator-id>withdrawalConsentDateStringValidator</validator-id>

                 <validator-class>your.validator.class.package.WithdrawalConsentDateStringValidator</validator-class>

                </validator>

              <validator>

               

               

              Make sure that WithdrawalConsentDateStringValidator implements javax.faces.validator.Validator; and then implements this method:

               

              public void validate(FacesContext facesContext, UIComponent uiComponent, bject value) throws ValidatorException

               

               

              I don't understand the <WithdrawalConsentDateString, String> bit. A validator should serve only one use case and if you want a variation, then you create another one.

               

               

              To confuse the matter a bit further,since you want to trigger and popup dialog, then validator may not do. You may need to process your action event in your backing bean and add code to validate and open the popup dialog if required.

               

              Cheers

              • 5. How to trigger custom annotated date validator.
                Sam W Expert

                Thank you very much for the tutorial. I have further implemented a simple Car case for testing purpose. http://docs.jboss.org/hibernate/validator/4.0.1/reference/en/html/validator-customconstraints.html

                It works perfectly, and I learnt what it is.

                 

                To reply Ben's suggestion, yes I agree the example I posted earlier is a complex validation.

                This is 2 of the many validation rules I am working on. Its logic flow is like this:

                If date is valid, then

                     popup dialog - yes : to go for other validations; no: go back to the same screen.

                else

                     display validation error message on the screen using JSF tags.

                 

                The popup dialog is easy once I can use  Custom Constraints validation  like the one shown in the link above to validate the date field.

                 

                Regarding to the validation defintion in faces-config.xml, since the whole team doesn't use faces-config.xml file at all, so I will have to stick with Custom Constraints validation.

                 

                Thanks a lot

                Sam

                • 6. How to trigger custom annotated date validator.
                  Sam W Expert

                  Hello,

                   

                  Is possible pass parameter bean / object into the validator?

                   

                  eg. I want to pass patientList into the @Date1050Constraint.

                   

                  This is my test class:

                   

                  public class WithdrawalConsentDatePageBean implements IBaseBean

                  {

                     

                      List<Patient> patientList;

                      

                      public List<Patient> getPatientList() { return patientList; }

                      public void setPatientList(List<Patient> list) { this.patientList = list; }

                   

                      @Date1050Constraint(patientList)

                      private String consentDate;   

                     

                      public String getConsentDate() {

                          return consentDate;

                      }

                   

                      public void setConsentDate(String consentDate) {

                          this.consentDate = consentDate;

                      }

                  }

                   

                  this is my Date1050Constraint class:

                   

                  @Target( { METHOD, FIELD, ANNOTATION_TYPE })

                  @Retention(RUNTIME)

                  @Constraint(validatedBy = Date1050Validator.class)

                  @Documented

                  public @interface Date1050Constraint {

                   

                      String message() default "Invalid withdrawal consent date - 1050.";

                   

                      Class<?>[] groups() default {};

                   

                      Class<? extends Payload>[] payload() default {};

                  }

                   

                  My Date1050Vaildator class:


                  public class Date1050Validator implements ConstraintValidator<Date1050Constraint, String> {

                   

                      @Override

                      public void initialize(Date1050Validation constraintAnnotation) {

                      }

                   

                      public boolean isValid(String dateString, ConstraintValidatorContext constraintContext)

                      {

                            //check dateString against dates in the PatientList.

                  ...

                      }

                  }

                   

                   

                  Thanks a lot

                  Sam

                  • 7. How to trigger custom annotated date validator.
                    Nicklas Karlsson Master

                    Well, in your validator implementation you are free to look up a BeanManager from JNDI and use it to fetch any available (e.g. @Produces) data.

                    • 8. How to trigger custom annotated date validator.
                      Sam W Expert

                      Hi Nicklas,

                       

                      Thanks for the suggestion.

                      I have tried the following implementation first, not srue if it is correct:

                       

                      Train.java:

                       

                      public class Train {

                          private String train;

                       

                          public String getTrain() {

                                  System.out.println(" ==== Train: getTrain() =======");

                                  return train;

                          }

                          public void setTrain(String consentDate) {

                                  System.out.println(" ==== train: setTrain() =======");

                                  this.train = consentDate;

                          }

                      }

                       

                      MyWrapper.java:

                       

                      public class MyWrapper 

                      {

                          @CheckCaseWithWrapper(CaseMode.UPPER)

                          private Train trains;

                       

                          public Train getTrains() {

                                  System.out.println(" ==== MyWrapper: getTrains() =======");

                                  return trains;

                          }

                       

                          public void setTrains(Train trains) {

                                  System.out.println(" ========== Wrapper: setTrains() ==========");

                                  this.trains = trains;

                          }

                             

                      }

                       

                      CheckCaseWithWrapper.java:

                       

                      @Target( { METHOD, FIELD, ANNOTATION_TYPE })

                      @Retention(RUNTIME)

                      @Constraint(validatedBy = CheckCaseValidatorWithWrapper.class)

                      @Documented

                      public @interface CheckCaseWithWrapper {

                       

                          String message() default "Case mode must be UPPER.";

                       

                          Class<?>[] groups() default {};

                       

                          Class<? extends Payload>[] payload() default {};

                         

                          CaseMode value();

                      }

                       

                      CheckCaseValidatorWithWrapper.java:

                       

                      public class CheckCaseValidatorWithWrapper implements ConstraintValidator<CheckCase, MyWrapper> {

                       

                          private CaseMode caseMode;

                       

                          @Override

                          public boolean isValid(MyWrapper object, ConstraintValidatorContext context) {

                              System.out.println("========== calling CheckCaseValidatorWithWrapper.isValid() ============== ");

                              if (object == null)

                                  return true;

                       

                              if (caseMode == CaseMode.UPPER)

                                  return true;

                              else

                                  return false;

                          }

                       

                      Test case:

                      public class TrainTest {

                       

                          private static Validator validator;

                       

                          @BeforeClass

                          public static void setUp() {

                              ValidatorFactory factory = Validation.buildDefaultValidatorFactory();

                              validator = factory.getValidator();

                          }

                       

                          @Test

                          public void testLicensePlateNotUpperCase() {

                       

                              Train train = new Train();

                              MyWrapper wrapper = new MyWrapper();

                              wrapper.setTrains(train);

                              Set<ConstraintViolation<MyWrapper>> constraintViolations =

                                  validator.validate(wrapper);

                              assertEquals(0, constraintViolations.size());

                      }

                      }

                       

                      From the result of running this test case, I found that there is no call to the Validator.

                      That means the wrapper doesn't even pick up the annotation @CheckCaseWithWrapper(CaseMode.UPPER) eventhought it is syntatically correct.

                       

                      What happened here?

                       

                      Thanks

                      sam

                      • 10. How to trigger custom annotated date validator.
                        Sam W Expert

                        I can get this to work no problem, because it is passing primitive type to the Validator.

                         

                        I am wondering how to pass CUSTOM type eg. MyWrapper to the validator. I can't find any example for doing that.

                         

                        Thanks

                        Sam

                        • 11. How to trigger custom annotated date validator.
                          Sam W Expert

                          What I meant is (Wrapper case):

                          public class CheckCaseValidatorWithWrapper implements ConstraintValidator<CheckCase, MyWrapper>

                          won't work,

                           

                          but (Primitive case):

                          public class CheckCaseValidatorWithWrapper implements ConstraintValidator<CheckCase, String>

                          works.

                           

                           

                          I need Wrapper case, in order to wrap other objects inside it.

                           

                          Thanks

                          Sam

                          • 12. How to trigger custom annotated date validator.
                            Sam W Expert

                            Array of primitive type works, shown as below:

                             

                            public class CheckCaseValidatorWithArray implements ConstraintValidator<CheckCaseWithArray, String[]> {

                             

                             

                                private CaseMode caseMode;

                             

                             

                                public void initialize(CheckCaseWithArray constraintAnnotation) {

                                    this.caseMode = constraintAnnotation.value();

                                }

                             

                             

                                public boolean isValid(String[] object, ConstraintValidatorContext constraintContext) {

                             

                             

                                    if (object == null)

                                        return true;

                             

                             

                                    if (caseMode == CaseMode.UPPER)

                                        return true;

                                    else

                                        return false;

                                }

                             

                             

                            }

                             

                            I am passing in String[] to the validator, then put a break point in side the inValid function, it stops there when it runs.

                            I think I will have to stuff all items in the String[] beforehand.

                             

                            Thanks

                            Sam

                            • 13. How to trigger custom annotated date validator.
                              Benjamin Seyinbour Expert

                              Where does ConstraintValidator come from? Is it your own class or from a library?

                               

                              If it is yours, you could do:

                               

                              interface ConstraintValidator<A extends CheckCase , T extends Serializable>{

                               

                              void initialize(A annotation);

                               

                              boolean isValid(T obj, ConstraintValidatorContext constraintContext);

                              ...

                              }

                              • 14. How to trigger custom annotated date validator.
                                Sam W Expert

                                Thanks that should work.

                                Another issue is I don't know how to trigger the validor from controller.

                                As the web page submit a form (eg.. when the user enter date), when the user press the submit button, I want the controller invoke my custom date validator.

                                 

                                At the moment, I have to "manually" invoke it by calling java voilationConstrant factory etc  in the dateAction() method.

                                 

                                Thanks

                                Sam

                                1 2 Previous Next