通过@ManagedProperty注入ResourceBundle似乎不能在@Named内部工作

时间:2015-01-20 12:41:54

标签: jsf cdi resourcebundle

如何从java代码访问消息包以根据当前区域设置获取消息?

我尝试使用@ManagedProperty,如下所示:

@Named 
@SessionScoped 
public class UserBean implements Serializable {

    @ManagedProperty("#{msg}")
    private ResourceBundle bundle;

    // ...

    public void setBundle(ResourceBundle bundle) {
        this.bundle = bundle;
    }

}

但是,它仍为null。它似乎在@Named内无效。

这是我在faces-context.xml中注册资源包的方式:

<application>

    <message-bundle>validator.messages</message-bundle>

    <locale-config>
        <supported-locale>en_US</supported-locale>
        <supported-locale>ua_UA</supported-locale>
    </locale-config>

    <resource-bundle>
        <base-name>lang.messages</base-name>
        <var>msg</var>
    </resource-bundle>

</application>

作者发表:

@BalusC我收到错误

16:29:10,968 ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/WEBSearchPrime_JB_lang].[Faces Servlet]] (http-localhost-127.0.0.1-8080-1) Servlet.service() for servlet Faces Servlet threw exception: org.jboss.weld.exceptions.IllegalProductException: WELD-000054 Producers cannot produce non-serializable instances for injection into non-transient fields of passivating beans\\n\\nProducer\: Producer Method [PropertyResourceBundle] with qualifiers [@Any @Default] declared as [[method] @Produces public util.BundleProducer.getBundle()]\\nInjection Point\: [field] @Inject private model.UserBean.bundle

请注意,我还放了Serializable接口

3 个答案:

答案 0 :(得分:9)

您无法在@ManagedProperty注释的CDI托管bean中使用@Named。您只能在使用@ManagedBean注释的JSF托管bean中使用它。

CDI没有任何注释来注入EL表达式的评估结果,如@ManagedProperty。 CDI方法使用带有@Produces的“CDI生成器”,其中返回具体类型,如果基于PropertyResourceBundle文件的资源包,则返回.properties

只需将此类放在WAR中的某个位置:

@RequestScoped
public class BundleProducer {

    @Produces
    public PropertyResourceBundle getBundle() {
        FacesContext context = FacesContext.getCurrentInstance();
        return context.getApplication().evaluateExpressionGet(context, "#{msg}", PropertyResourceBundle.class);
    }

}

现在您可以按如下方式注入它:

@Inject
private PropertyResourceBundle bundle;

答案 1 :(得分:1)

除了BalusC的答案:

自JSF 2.3起,还可以注入在faces-config.xml中定义的资源束,而无需使用生产方方法。有一个与javax.faces.annotation.ManagedProperty一起使用的新注释...annotation(注意,它在...bean包中,而不是@Inject包中):

// ...
import javax.faces.annotation.ManagedProperty;
// ...

@Named 
@SessionScoped 
public class UserBean implements Serializable {

  // ...

  @Inject
  @ManagedProperty("#{msg}")
  private ResourceBundle bundle;

  // ...

}

答案 2 :(得分:0)

也许我弄错了,但是实际上所提供的解决方案都不适合我的用例。因此,我提供了另一个对我有用的答案。

有了BalusC提供的答案,我遇到了以下问题:

  • 当我使用基于ajax的验证时,我的bean是@ViewScoped,并且 必须可序列化。既不是ResourceBundle也不是 PropertyResourceBundle是可序列化的,因此无法注入 @Dependent范围。

  • 如果我尝试将生产者更改为使用@RequestScoped,它也会失败 因为ResourceBundle不可用于定义final的代理 方法。

当我使用JSF 2.3(JBoss 7.2EAP)时,我采用了JörenHaag提供的解决方案,并且最初似乎可行。像原始问题一样,我也有多个受支持的语言环境,用户可以在语言环境之间进行切换(在我的情况下为caes

我遇到Jören答案的问题是

  • 创建bean时将评估返回的ResourceBundle。在他的示例中,他正在使用@SessionScoped bean。创建会话时,将使用当前语言环境解析ResourceBundle。如果用户以后更改语言环境,则ResourceBundle将不会更新。如果用户可以更改语言而不更改视图,则@ViewScoped bean也会发生这种情况。

  • 我还遇到了另一个需要使用<f:viewAction>预加载数据的bean问题。在这种情况下,bean是较早实例化的,因此在用ResourceBundle设置用户区域设置之前,注入了<f:view locale="#{sessionBean.locale}">。因此,如果用户浏览器使用的是es,但是用户将语言环境更改为ca,则捆绑包将加载es,因为视图语言环境未设置为{{1 }}和ca,直到呈现阶段。

要克服这个问题,对于使用注入的问题的用例,对我而言有效的解决方案是:

sessionBean.locale

由于原始问题不需要注入,因此仅询问如何使用当前语言环境访问资源束,无注入的解决方案以及每次{{1}都不会评估EL表达式@SessionScoped public class UserBean implements Serializable { @Inject @ManagedProperty("#{msg}") private Instance<ResourceBundle> bundle; // .... public void someAction() { String message = bundle.get().getString("someLabel"); // ... } } 的开销}称为:

#{msg}