1 Reply Latest reply on Jun 25, 2008 3:16 AM by dhinojosa

    Validator or Set question

    gzoller.greg.zoller.aviall.com

      Hello,


      I'm implementing a simple guess-the-number game in Seam to learn about validators.  I have a validator that checks to see if the user's guessed number falls in a min/max range, and that works.  If they enter non-integer junk in the input field I have provided what I hoped would be an exception to handle that with a message of my choosing.  Instead something is catching this problem before my validation and supplying some default error message that I don't want.


      Here's my JSF code snippet:


                <h:form id="numberForm">
                     <s:decorate>
                          <h:inputText type="text" id="userGuess" value="#{number.guess}" validator="#{number.validate}">
                          </h:inputText>
                          <s:message/>
                     </s:decorate>
                     <br/>
                     <h:commandButton value="Submit"/>
                </h:form>



      And here's code for my bean class that's also doing double duty as my validator.



      package com.mydomain.seamdemo;
      
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.faces.Validator;
      import java.util.Random;
      import javax.faces.application.FacesMessage;
      import javax.faces.component.UIComponent;
      import javax.faces.context.FacesContext;
      import javax.faces.validator.ValidatorException;
      
      @Name("number")
      @Scope(ScopeType.SESSION)
      @Validator
      public class NumberBean implements Number, javax.faces.validator.Validator {
           protected final static Random rand = new Random();
           
           protected int min;
           protected int max;
           protected int guess;
           protected int actual;
           protected int count;
           
           public NumberBean() {
                this.min = 1;
                this.max = 10;
                this.count = 0;
           }
           
           public void validate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
                try {
                     System.out.println("Entered: " + value.toString());
                     int param = Integer.parseInt(value.toString());
                     if( param > this.max || param < this.min ) {
                          this.count--;
                          FacesMessage msg = new FacesMessage("Guess must be between "+this.min+" and "+this.max);
                          throw new ValidatorException(msg);
                     }
                } catch(NumberFormatException e) {
                     this.count--;
                     FacesMessage msg = new FacesMessage("Must be a number");
                     throw new ValidatorException(msg);
                }
           }
           
           public synchronized int getActual() {
                if(this.actual==0) {
                     this.actual = rand.nextInt(this.max-this.min);
                     this.actual += this.min;
                }
                return this.actual;
           }
           
           public String getMessage() {
                this.count++;
                if( this.count == 1 )
                     return "Good luck!";
                if(this.guess == this.getActual()) {
                     return "Sweet, you got it right!";
                } else if( this.guess < this.getActual()) {
                     return "Sorry, try something higher";
                } else {
                     return "Too bad, go lower";
                }
           }
           
           public int getMin() {return this.min;}
           public int getMax() {return this.max;}
           public int getGuess() {return this.guess;}
           
           public void setMin(int min) {this.min = min;}
           public void setMax(int max) {this.max = max;}
           public void setGuess(int guess) {this.guess = guess;} 
           
           public void destroy() {}
      }
      



      You can see my attempt to catch NumberFormatException in my validate method but validate() never gets called if non-integer value is entered.  Why?  Or better--what can I do about it so I can get my desired message shown?


      The message I get on my rendered page when I enter non-integer values is this:


      value must be an integer number between -2147483648 and 2147483647


        • 1. Re: Validator or Set question
          dhinojosa

          The reason it never gets called is because in the JSF Application Lifecycle , conversion happens first. 


          One thing to remember, and something I had a hard time with in the beginning is that values need to be converted first to the type that it should be.  Then you can validate on that value. 


          In your case scenario, if you put a text value in there, the built in integer converter catches it first and the validator never gets called because the validator will never get called unless the value is a type that can be used.


          So the best bet is to just use the built in integer converter, and just change the messages in the Resource bundle to 'Must be a number'


          javax.faces.converter.IntegerConverter.INTEGER=value must be an integer
          javax.faces.converter.IntegerConverter.INTEGER_detail=value must be an integer number between -2147483648 and 2147483647
          


          and then you can use your validator to set the limits.  Since by the time the values come into your validator you can be assured that the values coming in are indeed at the right type.