3 Replies Latest reply on Mar 24, 2010 11:58 PM by kragoth

    h:selectOneRadio and converting to Short problem

      I would like to know how to use h:selectOneRadio with converters.

      I have a page with h:selectOneRadio value= tag all across the page with value binding to a backing bean parameter which is a Short type.

      Now the radio buttons in itself are Strings from 1 to 5.  I need it to convert it to Short so that when I save it into the object it can get saved as Short.

      I tried various combinations using s:convertEntity.
      Was told to use f:converter and provide ShortConverter as the id.
      Also tried using f:selectItems and s:selectItems
      None of them are working.

      Could someone provide a simple piece of code where they use
      h:selectOneRadio value being parameter of type Short.
      and f:selectItems list of Strings take for example 1 to 5 values as the radio buttons.

      Please provide some code.

      thanks
      Sai
        • 1. Re: h:selectOneRadio and converting to Short problem
          kragoth

          You really don't need to post your question on the forums more then once.



          Anyways, I'm pretty sure there is plenty of documentation about how to write a converter.
          So, if you can't figure out how to get the default converter working for you then write your own.
          They are very very simple to write.


          Here is my String converter (yes I have a String converter just to make blank/white space only/empty strings become null.)


          @Name(StringConverter.SEAM_ID)
          @org.jboss.seam.annotations.faces.Converter(id = "GekkoStringConverter")
          @SpringAutowirable
          public class StringConverter implements Converter {
              public static final String SEAM_ID = "StringConverter";
          
              @Override
              public Object getAsObject(
                  FacesContext context,
                  UIComponent component,
                  String value)
              {
                  if (StringUtils.isBlank(value)) {
                      return null;
                  }
                  
                  return value;
              }
          
              @Override
              public String getAsString(
                  FacesContext context,
                  UIComponent component,
                  Object value)
              {
                  if (!(value instanceof String)) {
                      throw new ConverterException(MessageFactory.getMessage(
                          context, "STRING_CONVERSION_ERROR,
                              value, MessageFactory.getLabel(context, component)));
                  }
                  
                  if (StringUtils.isBlank((String)value)) {
                      return "";
                  }
                  
                  return (String)value;
              }
          
          }
          



          Now, all you have to do is change it to make it convert Shorts instead of Strings.


          Then in your h:selectOneRadio make sure you specify converter=TheIdThatYouSpecifiedInThe @org.jboss.seam.annotations.faces.Converter Annotation

          • 2. Re: h:selectOneRadio and converting to Short problem

            Thanks for  your reply.  I noticed you used @SpringAutowirable. Is it that this can be used with Spring Framework also.

            • 3. Re: h:selectOneRadio and converting to Short problem
              kragoth

              The @SpringAutowirable is my own annotation that allows Spring beans to be @Autowired into my Seam Beans.


              If you would like to learn how to do this then see the code below.


              OK, so first the annotation class.


              @SpringAutowirable


              package gekko.web.services;
              
              import java.lang.annotation.Inherited;
              import java.lang.annotation.Retention;
              import java.lang.annotation.Target;
              
              import org.jboss.seam.annotations.intercept.Interceptors;
              
              import static java.lang.annotation.ElementType.TYPE;
              import static java.lang.annotation.RetentionPolicy.RUNTIME;
              
              @Target(TYPE)
              @Retention(RUNTIME)
              @Inherited
              @Interceptors(GekkoSpringInjector.class)
              public @interface SpringAutowirable {}
              



              So all this basically does is adds a Seam interceptor (GekkoSpringInjector.class) to all Seam Beans annotated with this annotation.


              Now the interceptor itself.


              GekkoSpringInjector.class


              package gekko.web.services;
              
              import java.lang.reflect.InvocationTargetException;
              
              
              import org.apache.log4j.Logger;
              import org.jboss.seam.annotations.intercept.Interceptor;
              import org.jboss.seam.intercept.AbstractInterceptor;
              import org.jboss.seam.intercept.InvocationContext;
              
              import gekko.util.ExceptionUtils;
              import gekko.web.utils.SeamUtils;
              import gekko.web.utils.WebUtils;
              
              
              @Interceptor
              public class GekkoSpringInjector extends AbstractInterceptor {
              
                  final private static Logger log =
                      Logger.getLogger(GekkoSpringInjector.class);
                  final private static Logger exceptionLog =
                      Logger.getLogger(
                          ExceptionUtils.EXCEPTION_STACK_PREFIX + "." +
                              GekkoSpringInjector.class.getName());
                  private static final String ERROR_STRING =
                      " Seam bean method execution threw an error";
              
                  @Override
                  public Object aroundInvoke(InvocationContext invocation) throws Exception {  // NOPMD
                      Object target = invocation.getTarget();
                      WebUtils.autowireSpringBeans(target);
              
                      Object result;
                      try {
                          result = invocation.proceed();
                      }
                      catch (InvocationTargetException ite){
                          String debugMethodInfo =
                              SeamUtils.constructDebugSignatureWithChoppedParams(invocation);
                          log.error(debugMethodInfo + ERROR_STRING);
                          exceptionLog.error(debugMethodInfo+ERROR_STRING, ite);
                          throw ite;  
                      }
                      catch (Exception e) {
                          String debugMethodInfo =
                              SeamUtils.constructDebugSignatureWithChoppedParams(invocation);
                          log.error(debugMethodInfo + ERROR_STRING);
                          exceptionLog.error(debugMethodInfo+ERROR_STRING, e);
                          throw e;
                      }
                      return result;
                  }
              
                  @Override
                  public boolean isInterceptorEnabled()
                  {
                     return true;
                  }
              
              }
              



              As you can see in that class I'm making some calls to some of my own Util classes. These calls are not important. They are just making exceptions easier to work with. I'm sure you can work out what info you want when something goes wrong.


              The only really important one is the call to WebUtils.autowireSpringBeans(target) so, I'll provide that code.


              From WebUtils.class


              public static void autowireSpringBeans(Object target) {
                      GekkoContainer container =
                          WebContextListener.getGekkoContainer( (ServletContext)
                              FacesContext.getCurrentInstance().getExternalContext().getContext() );
                  
                      container.getAutowireBeanFactory().autowireBeanProperties(
                          target,
                          AutowireCapableBeanFactory.AUTOWIRE_NO,
                          false);
                  }
              



              Now obviously here is where it gets a bit tricky because it is application specific. Essentially all that it is doing is getting the ApplicationContext and from that making the call to getAutowireCapableBeanFactory and then calling autowireBeanProperties on that passing in the Seam Bean.


              This does mean that you need to have a SpringApplicationContext (ours is a ClassPathXmlApplicationContext.class) available in your web layer. Hopefully you know enough about Spring to set all that up because I don't really have time to go into how our application is structured.




              After all that I think it is actually a mistake for me to have this interceptor on my converter. In fact the converter should probably be annotated with @BypassInterceptors, so, don't copy my bad practice. :P