views:

307

answers:

2

I have a properties file for localization:

foo=Bar
title=Widget Application

This is tied in as a resource-bundle in the faces-config:

<resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
</resource-bundle>

I can access this just fine in the facelets view using EL:

<title>#{msgs.title}</title>

However, if there are things like SQLExceptions, I need to be able to write messages from the managed bean. This is all working also:

FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);

Here is the issue: I want to have those messages come from the properties file so that they, too, can be changed based on the locale. Is there an easy way to access the properties file using injection?

A: 

Here's an example on how to do this: http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html

You want to have a look at the ResourceBundle.getBundle() part.

Greetings, Lars

Lars
I saw this when I googled it. However, is there a more elegant way to have the container inject this using @Resource("#{msgs}") or something like that? I suppose, since I'm using CDI, I could create a producer of `@MessageBundle` or something, and then just pass back a `Properties` object...
Zack
I used this approach in one of our last projects - we had the identical problem with DB errors. I can have a look at the old source on wednesday next week if this is still unsolved.
Lars
You're correct that it's a valid way to do it. I was just wondering if there was a way to do it more elegantly. I can just use CDI to inject it. That will work if there's no built-in annotation.
Zack
+1  A: 

I asked a quite related question on SO: http://stackoverflow.com/questions/3000170/how-to-inject-a-non-serializable-class-like-java-util-resourcebundle-with-weld

And inside the Seam Forum: http://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld

To summarize: I realized an injectable ResourceBundle with 3 Producers. First you need a FacesContextProducer. I took the one from the Seam 3 Alpha sources.

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

Then you need a LocaleProducer, which uses the FacesContextProducer. I also took it from Seam 3 Alpha.

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);
   }
}

Now you have everything to create a ResourceBundleProducer, which can look like this:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
    ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() )
  }
}

Now you can @Inject the ResourceBundle into your beans. Pay attention that it has to be injected into a transient attribute, otherwise you'll get an exception complaining that ResourceBundle is not serializable.

@Named
public class MyBean {
  @Inject
  private transient Resourcebundle bundle;

  public void testMethod() {
    bundle.getString("SPECIFIC_BUNDLE_KEY");
  }
}
ifischer