I want to create a Producer that makes it possible to inject a java.util.ResourceBundle into any class in order to get localized Strings easily. My ResourceBundle-Producer looks like this:
public class ResourceBundleProducer {
@Inject
public Locale locale;
@Inject
public FacesContext facesContext;
@Produces
public ResourceBundle getResourceBundle() {
return ResourceBundle.getBundle("/messages", locale )
}
}
The Injection of Locale and FacesContext works (took the corresponding producers from the Seam 3 Alpha Source). But unfortunately, ResourceBundle is not Serializable and therefore can't be produced in this way. 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? Or are there any other mechanisms to get a similar functionality? Thanks in advance!
EDIT:
Okay, i'll spent some of my hardly earned points ;) Will also accept a good workaround for this issue!
I got another example where creating a Producer doesn't work: a FlashProducer. A FacesContext-Flash also cannot be produced because Flash isn't serializable.
Well, First of all ResourceBundle is not Serializable. See here. And The message is clear
cannot produce non-serializable instances for injection into non-transient fields of passivating beans
passivating beans ??? I Think web.PersonHome is Either a Stateful Session Bean or a @ConversationScoped bean. Am i right ??? If so you should mark your bundle property as transient
private transient @Inject ResourceBundle bundle;
As per the comments thread in the accepted answer of Arthur. I followed this blog as well as this one to carry out a passivation/activation experiment. The experiment proved MrD comment that the transient property will be NULL upon activation. Thus, to deal with non-serializable member properties of a passivation capable bean (namely, sessionscoped, conversationscoped and stateful session beans), I suggest the following solution:
private ResourceBundle bundle;
@PostConstruct
@PostActivate
public void getResourceBundle() {
bundle = ResourceBundle.getBundle("/messages", locale );
}
This solution makes sure that the non-serializable property members are reinitialized every time it enters the READY state.
A final issue to address is the injection of an SLF4j Logger which was non-serializable before slf4j 1.5.3, and I quote:
As of SLF4J version 1.5.3, logger instances survive serialization. Thus, serialization of the host class no longer requires any special action, even when loggers are declared as instance variables.
Thus as long as your slf4j dependency is 1.5.3 or later you can safely inject an SLF4j Logger as follows:
@Produces
@LogbackLogger
public Logger produceLogger(InjectionPoint injectionPoint){
return LoggerFactory.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
Assuming you declared the qualifier:
@Qualifier
@Retention(RUNTIME)
@Target({METHOD, FIELD, PARAMETER, TYPE})
public @interface LogbackLogger {
}
Then in a passivation-capable bean, inject as follows:
@Inject
@LogbackLogger
private Logger logger;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With