6 Replies Latest reply on Dec 3, 2009 2:26 AM by charliebarjel

    Dependecny Injection in JSF Validator

      Hi Guys,


      I created a validator bean that implements the JSF Validator interface.
      The problem I have come across is Injecting my EntityHome component into the validator.


      Using



      @In(value = "siteVariableRelationHome", create = true, required = true)
      private SiteVariableRelationHome siteVariableQueryHome;



      always returns the siteVariableQueryHome object as NULL.


      I was however able to get a instance of my EntityHome object via




      SiteVariableRelationHome siteVariableQueryHome = (SiteVariableRelationHome) Component.getInstance("siteVariableRelationHome");




      Is anyone able to offer some insight into this and if its possible to use @In rather than call Component.getInstance().


      I read that the Validator is not a managed bean, and therefore you cannot use DI. Not sure if this is correct though?


      Thanks in advance.
      Charlie

        • 1. Re: Dependecny Injection in JSF Validator
          kragoth

          Please post your entire validator bean code as there's probably a few different ways this problem could happen.

          • 2. Re: Dependecny Injection in JSF Validator

            Here is my entire validator code:




            package au.com.statewater.koncentrator.action;
            
            import java.io.Serializable;
            import java.math.BigDecimal;
            import java.util.Iterator;
            
            import javax.el.ValueExpression;
            import javax.faces.application.FacesMessage;
            import javax.faces.component.NamingContainer;
            import javax.faces.component.UIComponent;
            import javax.faces.component.UIInput;
            import javax.faces.component.UIViewRoot;
            import javax.faces.context.FacesContext;
            import javax.faces.validator.Validator;
            import javax.faces.validator.ValidatorException;
            
            import org.jboss.seam.Component;
            import org.jboss.seam.ScopeType;
            import org.jboss.seam.annotations.In;
            import org.jboss.seam.annotations.Logger;
            import org.jboss.seam.annotations.Name;
            import org.jboss.seam.annotations.Scope;
            import org.jboss.seam.annotations.intercept.BypassInterceptors;
            import org.jboss.seam.log.Log;
            
            import au.com.statewater.koncentrator.action.home.SiteVariableRelationHome;
            import au.com.statewater.koncentrator.entity.SiteVariableRelation;
            import au.com.statewater.koncentrator.entity.SiteVariableRelationId;
            
            @Name("readingValidator") 
            @Scope(ScopeType.CONVERSATION)
            @org.jboss.seam.annotations.faces.Validator
            @BypassInterceptors
            public class ReadingValidator implements Validator, Serializable {
            
                 /**
                  * Auto-generated Id
                  */
                 private static final long serialVersionUID = 1169110644691617222L;
                 
                 @Logger Log log;
            
                 //@In(value = "siteVariableRelationHome", create = true, required = true)
                 //private SiteVariableRelationHome siteVariableQueryHome;
                 
                 private final String ATTRIBUTE_Panel           = "attrPanel";
                 private final String ATTRIBUTE_FormTable      = "attrFormTable";
                 private final String ATTRIBUTE_SiteId           = "attrSiteId";
                 private final String ATTRIBUTE_VaribleId      = "attrVariableId";
                 
            
                 @Override
                 public void validate(FacesContext context, UIComponent component, Object value)
                           throws ValidatorException {
                      
                      String readingValue = (String) value;
                      
                      String siteId           = getSelectedSiteId(context, component);
                      String variableId      = getSelectedVariableId(context, component);
                      
                      SiteVariableRelationId id = new SiteVariableRelationId(siteId, variableId);
                      
                      SiteVariableRelationHome siteVariableQueryHome = (SiteVariableRelationHome) Component.getInstance("siteVariableRelationHome");
                      
                      siteVariableQueryHome.setSiteVariableRelationId(id);
                      
                      SiteVariableRelation svRelation = siteVariableQueryHome.getInstance();
                      
                      BigDecimal minValue = svRelation.getMinValue();
                      BigDecimal maxValue = svRelation.getMaxValue();
                      
                      if (!newReadingValid(readingValue, minValue, maxValue)) {
                           throw new ValidatorException(new FacesMessage("Reading is not between allowed values (Min: " + minValue + " - Max: " + maxValue + ")"));
                      }
            
                 }
                 
                 private boolean newReadingValid(String readingValue, BigDecimal minValue, BigDecimal maxValue) {
                      Integer reading;
                      
                      try {
                           reading = Integer.parseInt(readingValue);
                      
                           if ((reading.intValue() >= minValue.intValue()) && reading.intValue() <= maxValue.intValue()) {
                                return true;
                           }
                      } catch (NumberFormatException nfe) {
                           // Cannot parse reading - Not integer
                           return false;
                      } catch (NullPointerException npe) {
                           // Variable has no MIN and MAX values
                           return true;
                      }
                      return false;
                 }
                 
                 private String getSelectedSiteId(FacesContext context, UIComponent component) {
                      
                      String attributeSiteId = (String) component.getAttributes().get(ATTRIBUTE_SiteId);
                      
                      UIComponent readingsTable = getFormTable(context, component);
                      
                      UIInput siteId = (UIInput) readingsTable.findComponent(attributeSiteId);
                                
                      return (String) siteId.getValue();
                      
                 }
                 
                 private String getSelectedVariableId(FacesContext context, UIComponent component) {
                      
                      String attributeVariableId = (String) component.getAttributes().get(ATTRIBUTE_VaribleId);
                      
                      UIComponent readingsTable = getFormTable(context, component);
                      
                      UIInput variableId = (UIInput) readingsTable.findComponent(attributeVariableId);
                                
                      return (String) variableId.getValue();
                      
                 }
                 
                 /**
                  * Find and return the JSF Form Table component that contains the form field values
                  * @param context invoked context
                  * @param component component containing attribute values
                  * @return form table component
                  */
                 private UIComponent getFormTable(FacesContext context, UIComponent component) {
                      
                      String attributePanel           = (String) component.getAttributes().get(ATTRIBUTE_Panel);
                      String attributeFormtable      = (String) component.getAttributes().get(ATTRIBUTE_FormTable);
                      
                      // Find JSF root component
                      UIComponent readingsPanel = context.getViewRoot().findComponent(attributePanel);
                      
                      // Find JSF Form Table component that contains form fields
                      return readingsPanel.findComponent(attributeFormtable);
                 }
            
            }
            



            Thanks for your help.


            Charlie

            • 3. Re: Dependecny Injection in JSF Validator
              kragoth

              Alrighty, your problem is all because of one line of code you have.


              @BypassInterceptors
              



              I would really recommend reading the doco surrounding this annotation, but I'll try explain simply.


              The @BypassInterceptors annotation does exactly what it sounds like. It means the Seam interceptors will bypass this bean. The Seam interceptors will not fire on this bean. Now, Bijection is done BY an interceptor. So, if you put this annotation on your class Bijection will never occur becuase you have told Seam to not intercept it.


              Now, on a validator I believe it is actually recommended to have the @BypassInterceptors annoatation present so... you are basically limited to using Component.getInstance(Bean.class) or any variants of Component.getInstance() to get an instance of a Seam bean.



              On a side note, are Validators normally Conversation scoped? Seems a little odd to me, but I could be wrong.


              I hope this helps a little. I'll try keep an eye on the thread incase you have more questions.

              • 4. Re: Dependecny Injection in JSF Validator

                Thanks for your help Tim.


                It make sense to me now.
                And you're right, I need the @BypassInterceptors on the validator.


                So I might have to stick to Component.getInstance().


                Just a quick question though on something you mentioned...what is the best scope for my validator to sit in?


                Thanks again


                Charlie

                • 5. Re: Dependecny Injection in JSF Validator
                  kragoth

                  Hey Charlie,


                  I was always under the impression that Validators are Event scoped.


                  Looking into the Seam examples I came across this Validator.


                  @Name("wikiCaptchaValidator")
                  @Validator(id = "wikiCaptchaValidator")
                  public class WikiCaptchaValidator implements javax.faces.validator.Validator, Serializable {
                  



                  Notice the lack of the @Scope annotation. From my understanding this means that it would be Event scoped.


                  That being said, I can't think of any reason why Conversation scope will give you a problem, I just don't think it's considered necessary.


                  Anyways, I'm glad you've got a good understanding of what's going on now.


                  Cheers,
                  Tim

                  • 6. Re: Dependecny Injection in JSF Validator

                    Thanks again for your help Tim.


                    Appreciate it.