8 Replies Latest reply on May 19, 2010 8:59 AM by Craig Bensemann

    Dynamic parameter for custom converter

    Holger L Newbie
      Hi,

      I'm trying to dynamically scale BigDecimals in a converter. Here're some snippets of my code

      Converter:
      public class AmountConverter implements Converter {
        private Integer amountScale;
             
        @Override
        public Object getAsObject(FacesContext context, UIComponent component, String value) {
         //... use amountScale to scale the BigDecimal
        }
        @Override
        public String getAsString(FacesContext context, UIComponent component, Object value) {
        //... use amountScale to scale the BigDecimal
        }

        public Integer getAmountScale() {
          return amountScale;
        }
        public void setAmountScale(Integer amountScale) {
          this.amountScale = amountScale;
        }
      }

      faces-config.xml:
      ...<converter>
        <converter-id>amountConverter</converter-id>
        <converter-class>com.test.msg.ce.ui.convert.AmountConverter</converter-class>
          <property>
              <property-name>amountScale</property-name>
              <property-class>java.lang.Integer</property-class>
          </property>          
      </converter>...

      taglib.xml:
      <?xml version="1.0"?>
      <!DOCTYPE facelet-taglib PUBLIC
        "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
        "facelet-taglib_1_0.dtd">
      <facelet-taglib>
        <namespace>...</namespace>
             
        <tag>
          <tag-name>amountConverter</tag-name>
            <converter>
              <converter-id>amountConverter</converter-id>
            </converter>
          </tag>
      ...


      xhtml file:
      ...
      <h:outputText value="#{margin.dollarMargin}" converter="amountConverter">
        <comm:amountConverter amountScale="#{margin.rateType.amountScale}" />
      </h:outputText>...

      When I enter a static value for the amountScale attribute it works fine i.e. the converter receives the correct amountScale. However, with an EL i.e. amountScale="#{margin.rateType.amountScale}" the received amountScale in the AmountConveter is always null. Are ELs not being evaluated in this case? The value is definitely not null (I used a outputText to verify)!

      Is there another way to get the amountScale in the AmountConverter?

      Cheers
        • 1. Re: Dynamic parameter for custom converter
          Holger L Newbie

          Nobody knows a solution for this?

          • 2. Re: Dynamic parameter for custom converter
            Craig Bensemann Novice

            Hi,


            I haven't done this before but my approach would be:


            Create your validator and register using Seam annotations not faces-config.xml


            @Name("myConverter")
            @BypassInterceptors
            @org.jboss.seam.annotations.faces.Converter
            public class MyConverter implements Converter {
            
               private String myVariable;
            ...
            }



            This way Seam does all the hard work for you and you dont need the xml configuration.


            Because we must have BypassIntercetors you cant inject variables so I would create an init method like this:


            @Create
            public void init() {
                myVariable = (String) Expressions.instance().createValueExpression("#{myELExpression}").getValue();
            }
            



            This way when the component is initialised it looks up the expression and assigns the variable. I'm not sure this is the correct way but I modified one of my converters just now to test it and it appears to work.



            Craig

            • 3. Re: Dynamic parameter for custom converter
              Holger L Newbie
              Hi Craig,

              Thanks for your reply. I've removed the entries in the faces-config.xml and taglib.xml and added the annotations to the Converter class (so far withouth the @Create):

              @Name(value="amountConverter")
              @BypassInterceptors
              @Converter
              public class AmountConverter implements javax.faces.convert.Converter {
              ...
              }

              <rich:column id="amount" sortBy="#{margin.cashMargin}" sortOrder="UNSORTED" style="text-align: right" >
              <f:facet name="header">
              <h:outputText styleClass="headerText" value="Rate %" />
              </f:facet>
              <h:outputText value="#{margin.cashMargin}" converter="amountConverter"/>
              </rich:column>

              However, I'm getting a "Expression Error: Named Object: amountConverter not found.". This is the first time I'm using Seam annotations to register a component. Is there anything else required in web.xml, components.xml? It worked fine with the fconfig in faces-config.xml and taglib.xml... I would have thought this works in Seam 2.2.0GA? Thanks!
              • 4. Re: Dynamic parameter for custom converter
                Craig Bensemann Novice

                Hi,


                you will just need to change converter="amountConverter" to be converter="#{amountConverter}"


                hope that helps.

                • 5. Re: Dynamic parameter for custom converter
                  Holger L Newbie
                  Hmmm... seems like the converter is not called at all anymore. How would it look if <f:converter convertId="???"/> was to be used?

                  Do I need a @Convert(id="amountConverter")?
                  • 6. Re: Dynamic parameter for custom converter
                    Craig Bensemann Novice

                    Well that's odd.


                    Here's a complete example I am using in a project


                    /**
                     * Copyright Software Factory - 2010
                     */
                    package nz.co.softwarefactory.risingstars.seam;
                    
                    import javax.faces.component.EditableValueHolder;
                    import javax.faces.component.UIComponent;
                    import javax.faces.context.FacesContext;
                    import javax.faces.convert.Converter;
                    
                    import org.jboss.seam.annotations.Name;
                    import org.jboss.seam.annotations.intercept.BypassInterceptors;
                    
                    /**
                     * 
                     * @author craig
                     */
                    @Name("risingstars.emptyToNullConverter")
                    @BypassInterceptors
                    @org.jboss.seam.annotations.faces.Converter
                    public class EmptyToNullConverter implements Converter {
                    
                        public Object getAsObject(final FacesContext facesContext, final UIComponent component, final String value) {
                            if (value == null || value.trim().length() == 0) {
                                if (component instanceof EditableValueHolder) {
                                    ((EditableValueHolder) component).setSubmittedValue(null);
                                }
                                return null;
                            }
                            return value;
                        }
                    
                        public String getAsString(final FacesContext facesContext, final UIComponent component, final Object value) {
                            return value == null ? null : value.toString();
                        }
                    
                    }
                    



                    and its usage:


                    <h:inputText value="#{viewOrganizationStructureController.selectedNode}" required="true" converter="#{emptyToNullConverter}" />



                    I have imported the risingstars namespace in my components.xml so I dont need to fully qualify the reference to the converter.


                    I have about 3 different converters in my current project and all are defined this way. I'm pretty sure thats all you need to do.


                    As for trying it with an f:converter I would imagine you would specify it the way you have suggested: @Converter(id="amountConverter") <f:converter converterId="amountConverter" /> but I have not tried this.


                    Let me know how you go
                    Craig


                    • 7. Re: Dynamic parameter for custom converter
                      Holger L Newbie
                      Using the converterId field results in a "Expression Error: Named Object: ' not found." for both #{amountConverter} and #{amountConverter.id}

                      Could you post your components.xml since I'm very new to seam and am not sure how to include the namepsace. Are you able to remote debug into the converter?

                      Thanks for your help
                      • 8. Re: Dynamic parameter for custom converter
                        Craig Bensemann Novice

                        I run JBoss from inside eclipse and can debug the converters. This should be just the same as running JBoss externally and remote debugging it.


                        In my components.xml I have <import>risingstars</import> this means that I can access my converter by using emptyToNullConverter rather than the full risingstars.emptyToNullConverter This is true for any components and is why you can access seam components like identity by the name identity rather than its full component name org.jboss.seam.security.identity But this is a little off topic I guess.


                        I'm not really sure what else to suggest. It should just work. Does anyone else reading this thread have any suggestions?


                        I'll look back over my code but I think I have given you a full working example and no other code is required.