如何使用Weld注入非可序列化的类(如java.util.ResourceBundle)

时间:2010-06-08 18:30:33

标签: java-ee java-ee-6 cdi jboss-weld

我想创建一个Producer,它可以将java.util.ResourceBundle注入任何类,以便轻松获取本地化的Strings。我的ResourceBundle-Producer看起来像这样:

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
    return ResourceBundle.getBundle("/messages", locale )
  }
}

Locale和FacesContext的注入工作(从Seam 3 Alpha Source中获取相应的生成器)。但不幸的是,ResourceBundle不是Serializable,因此无法以这种方式生成。当我尝试访问一个调用使用我的ResourceBundle的bean的JSF页面时,我从Weld得到以下错误:

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

有没有办法让我的ResourceBundleResolver工作?或者是否有其他机制来获得类似的功能? 提前谢谢!

修改

好的,我会花一些难以获得的积分;) 对于这个问题,也会接受一个很好的解决方法!

我有另一个例子,创建一个Producer不起作用:一个FlashProducer。还无法生成FacesContext-Flash,因为Flash不可序列化。

2 个答案:

答案 0 :(得分:25)

好吧,首先,ResourceBundle 不可序列化。见here。信息很明确

  

无法生成非序列化实例,以便注入钝化bean的非瞬态字段

钝化豆 ???我认为 web.PersonH​​ome 是有状态会话Bean或@ConversationScoped bean。我对吗 ???如果是这样,您应将您的捆绑属性标记为瞬态

private transient @Inject ResourceBundle bundle;

答案 1 :(得分:3)

根据Arthur接受的答案中的评论主题。我跟着this blog以及this one进行了钝化/激活实验。实验证明MrD评论说,瞬态属性在激活时将为NULL。因此,为了处理具有钝化能力的bean的非可序列化成员属性(即,sessioncoped,conversationscoped和有状态会话bean),我建议采用以下解决方案:

private ResourceBundle bundle;

@PostConstruct
@PostActivate
public void getResourceBundle() {
    bundle = ResourceBundle.getBundle("/messages", locale );
}

此解决方案确保每次进入READY状态时都会重新初始化非序列化属性成员。

要解决的最后一个问题

要解决的最后一个问题是注入一个SLF4j Logger,它在slf4j 1.5.3和I quote之前是不可序列化的:

  

从SLF4J 1.5.3版开始,记录器实例在序列化后继续存在。   因此,主机类的序列化不再需要任何特殊的   即使将记录器声明为实例变量也是如此。

因此,只要您的slf4j依赖关系是1.5.3或更高版本,您就可以安全地注入SLF4j Logger,如下所示:

@Produces
@LogbackLogger
public Logger produceLogger(InjectionPoint injectionPoint){
    return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}

假设你宣布了限定符:

@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface LogbackLogger {
}

然后在具有钝化能力的bean中,注入如下:

@Inject
@LogbackLogger
private Logger logger;