5 Replies Latest reply on Feb 16, 2009 11:19 PM by Binesh Gummadi

    Custom Validator for Hibernate only runs on persist

    Steffen Persch Newbie

      Hi together,


      first I want to introduce myself. I am Steffen Persch from Germany, I'm 22years old and I have been java coder for now 2,5 years and seam coder for 1year.


      I was searching for a solution for my problem but I did not find anyone. I have written a custom Validator for Hibernate (code below) and it works, but only when I called my entityManager with a persist. What have I to do now that it will work with <s:validateAll> ?


      Sry for my non perfect English, I hope you understand me.


      Here my classes:



      package de.dssc.validator;
      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(DSSCImageValidator.class)
      @Target({FIELD, METHOD})
      @Retention(RUNTIME)
      @Documented
      public @interface ImageValidator {
      
        /** @return error message key */
        String message() default "{validator.imageValidator}";
      }





      package de.dssc.validator;
      
      import java.util.*;
      
      import org.hibernate.validator.*;
      
      public class DSSCImageValidator implements
          Validator<ImageValidator> {
      
          private static final Set<byte[]> VALID_HEX_BYTES = new HashSet<byte[]>();
          static {
              byte[] jpeg = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE0};
              VALID_HEX_BYTES.add(jpeg);
              byte[] jpegExif = {(byte) 0xFF, (byte) 0xD8, (byte) 0xFF, (byte) 0xE1};
              VALID_HEX_BYTES.add(jpegExif);
              byte[] jpegQM = {(byte) 0x4A, (byte) 0x46, (byte) 0x49, (byte) 0x46};
              VALID_HEX_BYTES.add(jpegQM);
          }
          
          public boolean isAllowedType(byte[] firstBytes) {
              for (byte[] byteArr : VALID_HEX_BYTES) {
                  if (Arrays.equals(byteArr, firstBytes)) {
                      return true;
                  }
              }
              return false;
          }
      
          public void initialize(ImageValidator arg0) {
              // TODO Auto-generated method stub
              
          }
      
          public boolean isValid(Object obj) {
              System.out.println("DSSC IMAGE VALIDATOR: Validator called!");
              
              final byte[] imageData = (byte[]) obj;
              final byte[] firstBytes = Arrays.copyOfRange(imageData, 0, 4);
              if(!isAllowedType(firstBytes)) {
                  return false;
              }
              return true;
          }
      
      }



      And my field in the entity:


      @Lob
      @Basic(fetch=FetchType.LAZY)
      @Column(columnDefinition = "MEDIUMBLOB")
      @ImageValidator(message = "pic error message")
      private byte[] picture;



      Best regards
      Steffen

        • 1. Re: Custom Validator for Hibernate only runs on persist
          Binesh Gummadi Novice

          If I understood it right, you want to have ajax validation in your xhtml so it would immediately show the error message?


          Show us your xhtml file.


          • 2. Re: Custom Validator for Hibernate only runs on persist
            Steffen Persch Newbie

            No, ajax validation is not the problem. Normally when I click the next-button and any field is invalid I get an error in the facesMessages (<h:messages />) but not at this field, so I get only an validationFailed exception in the console. If the input is correct, all works fine.


            Here is my xhtml file, reduced to the important things and the method i call up by #{registration.register}:



            <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
            <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                  xmlns:ui="http://java.sun.com/jsf/facelets"
                  xmlns:h="http://java.sun.com/jsf/html"
                  xmlns:f="http://java.sun.com/jsf/core"
                  xmlns:s="http://jboss.com/products/seam/taglib"
                  xmlns:rich="http://richfaces.org/rich"
                  template="template.xhtml">
                <ui:define name="content">
                    <s:div layout="block" styleClass="conwrapper">
                        <h:messages styleClass="errorList" />
                        <form jsfc="h:form" enctype="multipart/form-data">
                            <s:validateAll>
                            <fieldset class="personalData">
                                <legend>Persönliche Informationen</legend>
                                <label for="picture" jsfc="h:outputLabel">Benutzerbild:</label>
                                <s:fileUpload id="picture" data="#{driver.picture}" accept="image/*" required="true" requiredMessage="Benutzerbild erforderlich" />
                            </fieldset>
                            <input type="submit" value="Anmeldung abschliesen" action="#{registration.register}" jsfc="h:commandButton" styleClass="finreg" />
                            </s:validateAll>
                        </form>
                    </s:div>
                </ui:define>
            </ui:composition>




            public String register() {
                    
                    driver.setDriverType(driverType);
                    driver.setCrafts(crafts);
                    
                    if (null != oldDriver) {
                        em.remove(em.merge(oldDriver));
                    }
                    
                    if (null == driver.getDriverNo()) {
                        final ComputeRangeNo computeDN = new ComputeRangeNo(driverType, em);
                        final Integer newDriverNo = computeDN.compute();
                        log.info("Generated new DriverNo: " + newDriverNo);
                        driver.setDriverNo(newDriverNo);
                    }
                    
                    final PwdGenerator pwdGenerator = new PwdGenerator();
                    final EncryptService es = new EncryptService(pwdGenerator.getPassword(8));
                    this.newPassword = es.generatePasswordString("MD5");
                    driver.setPassword(newPassword);
                    
                    em.persist(driver);
                    renderer.render("/mail-registrationSuccess.xhtml");
                    log.info("Fahrer " + driver.getFirstName() + " " + driver.getLastName() + " gespeichert. (" + driver.getId() + ")");
                    return "/regged";
                    
                }

            • 3. Re: Custom Validator for Hibernate only runs on persist
              Binesh Gummadi Novice

              I looked at your code carefully and thats exactly how it should be. try to use h:messages with globalonly set to true and see if it is displaying the error message.

              • 4. Re: Custom Validator for Hibernate only runs on persist
                Steffen Persch Newbie

                I dont think that the <h:messages /> is the problem. My validator class is only called up on the persist, not before. Do I have to register my validator on any settings file that it is called up of the event type pre-persist / pre-validate?

                • 5. Re: Custom Validator for Hibernate only runs on persist
                  Binesh Gummadi Novice

                  You don't have to register.


                  I fire onblur event and validation happens right away. At some point I had to implement Serializable to make it work but don't really remember why and what version of hibernate and seam.