5 Replies Latest reply on Aug 29, 2014 6:18 AM by timo.krumscheid

    How to create an injectable Resourcebundle with Weld

      In my Java EE 6 application, i'm often dealing with the ResourceBundle in my Beans to get localized messages. To get the correct ResourceBundle, i always have to obtain it in this way:


      FacesContext facesContext = FacesContext.getCurrentInstance();
      String sessionErrorString = ResourceBundle.getBundle("/messages", 
           facesContext.getViewRoot().getLocale()).getString("sessionTimeOut")
      



      So i always have to obtain the instance of FacesContext and resolve the locale.
      As this is not very elegant, i looked into the Seam 3 Source and found some nice producer classes, i.e. for the Locale and for the FacesContext.
      Now i want to use them to create a ResourceBundle-Producer, so i can shorten the above code by injection to the following:


      @Inject ResourceBundle bundle;
      (...)
      public void test() {
        log.info(bundle.getString("myMessage"));
      }
      



      So these are the classes i obtained from the current Seam 3-trunk. I need them for my BundleResolver:


      FacesLocaleResolver:


      public class FacesLocaleResolver {
         @Inject
         FacesContext facesContext;
      
         public boolean isActive() {
            return (facesContext != null) && (facesContext.getCurrentPhaseId() != null);
         }
      
         @Produces @Faces
         public Locale getLocale() {
            if (facesContext.getViewRoot() != null) 
               return facesContext.getViewRoot().getLocale();
            else
               return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
         }
      }
      



      FacesContextProducer:


      public class FacesContextProducer {
         @Produces @RequestScoped
         public FacesContext getFacesContext() {
            FacesContext ctx = FacesContext.getCurrentInstance();
            if (ctx == null)
               throw new ContextNotActiveException("FacesContext is not active");
            return ctx;
         }
      }
      



      And this shall be my ResourceBundle-Resolver:


      public class ResourceBundleProducer {
        @Inject       
        public Locale locale;
        
        @Inject       
        public FacesContext facesContext;
      
        @Produces
        public ResourceBundle getResourceBundle() {
          ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() )
        }
      }
      



      Unfortunately, my BundleResolver doesn't work, as ResourceBundle is not Serializable. I'm getting the following Error from Weld when trying to access a JSF-page which calls a bean that uses my ResourceBundle:


      Caused by: org.jboss.weld.IllegalProductException: WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: org.jboss.weld.bean-/D:/Program Files (x86)/GlassFish-Tools-Bundle-For-Eclipse-1.2/glassfishv3/glassfish/domains/teachernews/applications/teachernews/-ProducerMethod-services.producers.ResourceBundleProducer.getResourceBundle()\\nInjection Point\: field web.PersonHome.bundle
      



      Are there any ways to get my ResourceBundleResolver to work? Can i somehow wrap ResourceBundle and make it serializable? Or are there any other mechanisms to get a similar functionality?
      Thanks in advance!