1

first of all, sorry for my bad english!

in the following managed Bean (ApplicationScoped), i access a ResourceBundle(.properties) as a @ManagedProperty. a ResourceBundle Object is not serializable, so i get in the Eclipse/Tomcat Console an Error saying that this object cannot be serialized/de-serialized.. etc.

Exception loading sessions from persistent storage java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: java.util.PropertyResourceBundle

i have 2 Questions to this issue:

  • i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans. this means(if i understanding this correctly), this Object/Bean (ResourceBundle) is been stored somewhere somehow in a file (persistent storage). Now and since ResourceBundle is not serializable, then in which format is it been stored? and how JSF serves such "Beans"? serialized Objects are stored in files as Bytes, so how not serializable Objects are stored?
  • in the following example, i would declare my @ManagedProperty ResourceBundle as transient (due to serialization problem), but transient objects won't be stored in persistent storage (stateless), does this mean that with every call of the method getConfigurationAttribute(where i use this resourceBundle) will recreate/reload the ManagedPropery ResourceBundle since it is marked as transient?

Your help is greatly appreciated.

@ManagedBean(name="facesResource",eager=true)
@ApplicationScoped
public class FacesResource implements Serializable{
    private static final long serialVersionUID = 2454454363100273885L;
    @ManagedProperty("#{FACES_CONFIG}")
    private ResourceBundle facesConfig;
    //private transient ResourceBundle facesConfig;

    ....
    private Map<String,Language> languagesMap;  
    private Map<String,Theme> themesMap;
    ....

    public FacesResource(){

    }
    @PostConstruct
    public void init(){
        System.out.println("*** FacesResource init ....");
        try{
            ....
            this.initLanguages();
            this.initThemes();
            ....
        }catch(Exception ex){
            ex.printStackTrace();
        }
    }       

    public String getConfigurationAttribute(String attributeKey){
        return this.facesConfig.getString(attributeKey);
    }
    // ... other methods & getter/setter ...etc

}

UPDATE:

  • the ResourceBundle in the FacesResource Bean is independent of the Request Locale, so its not a problem to load it in an ApplicationScoped Bean, BUT

  • since i access/inject(as @ManagedProperty) this ApplicationScoped Bean in other SessionScoped Beans, which should be serialized, which means, that all attributes (resourceBundle included) should be serialized too, and here i got the Problem with Serialization/Deserializazion

  • @BalusC: if i do like you suggest in your answer: ResourceBundle.getBundle("com.example.text"), i have to provide the baseName of the Bundle. BUT this is exactly what i want to avoid. i don't want to hardcode static Paths in java Source Codes), so that when the path changes(most unlikely, but for the Case), i don't like to change paths in Java Source Codes but only in faces-config.xml.

  • and i cannot use FacesContext.getCurrentInstance().getApplication().getResourceBundle(facesContext, "bundleVarName"); because my Bean is marked with eager=true, which means, the facesContext is NULL at this moment!

Rami.Q
  • 2,486
  • 2
  • 19
  • 30

2 Answers2

1

i think, JSF handles pre-defined(in faces-config.xml) ResourceBundles as ApplicationScoped beans.

Nope. They are managed by ResourceBundle API itself. JSF just resolves them on a per-request basis based on the requested locale (otherwise it would affect the language of any user visiting the web application!). So, they are essentially request scoped. But this all has further nothing to do with serialization. The ResourceBundle class is simply never intented to be serializable. It just lazily loads the bundles in Java's memory.

You'd best just do the same. Lazy loading it if it becomes null after deserialization. You only shouldn't evaluate #{FACES_CONFIG}, because it would be dependent on request locale. Provided that you can only use JSF <resource-bundle><var>, then you'd best load them via Application#getResourceBundle(). Provided a resource bundle var name of FACES_CONFIG, here's an example:

private transient ResourceBundle facesConfig;

public ResourceBundle getFacesConfig() {
    if (facesConfig == null) {
        FacesContext context = FacesContext.getCurrentInstance();
        facesConfig = context.getApplication().getResourceBundle(context, "FACES_CONFIG");
    }

    return facesConfig; 
}

By the way, the variable name facesConfig is very confusing. It namely suggests that it represents the contents of faces-config.xml.

See also:

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • thanks BalusC, i see your answer http://stackoverflow.com/questions/6272945/how-can-i-get-a-message-bundle-string-from-inside-a-managed-bean, and you suggested that we can use ResourceBundle as ManagedProperty, is it only good for requestScoped Beans, because its loaded evry time since its in requestScope? the name FACES_CONFIG is related to the Project Name (YouFaces), not the faces-config.xml. – Rami.Q Jul 15 '15 at 17:22
  • As resource bundles are request scoped, `@ManagedProperty` on a resource bundle indeed works in a request scoped bean only. It's however possible with CDI `@Inject` with little help of a custom producer. As per your question update, you should just be able to get hand of `FacesContext` in `@PostConstruct`, even in an eagerly initialized application scoped bean. I updated the answer to just do the job in the lazy loading getter. – BalusC Jul 15 '15 at 20:03
  • thank you very much BalusC. would you please explaine to me why/how is FacesContext available before/without any Request? i thought FacesContext is only available after the most first request. – Rami.Q Jul 15 '15 at 20:35
  • During startup there's a special "init" `FacesContext`. It will have all application wide stuff ready in a.o. `getApplication()`, but e.g. the methods of `ExternalContext` may indeed not have the desired effects at that point. But you don't need them in such case anyway. – BalusC Jul 15 '15 at 20:36
0

You can't use @ManagedProperty on a not Serializable Type.

Is it a resource bundle for localized Strings?

Read this: http://www.mkyong.com/jsf2/jsf-2-0-and-resource-bundles-example/

FacesContext facesContext = FacesContext.getCurrentInstance();
ResourceBundle resourceBundle = facesContext.getApplication()
                                       .getResourceBundle(facesContext, "bundleName");
  • thanks, but since JSF 2.2, i can access ResourceBundle as @ManagedProperty! – Rami.Q Jul 15 '15 at 00:00
  • Oh, i didn't see the tag "jsf-2.2". I don't know much about 2.2 version, but i keep my point about using @ManagedProperty on not Serializable Type. I think you can only access a single property of bundle mapped on faces-config.xml. "@ManagedProperty("#{bundleVar['property_text']}") String text". You are sure that the Type is directly accessible? Where did you read about accessing the ResourceBundle in this way? I want read about it :) – Leandro Hinckel Silveira Jul 15 '15 at 12:19
  • yes the Type is directly accessible as @ManagedProperty i tested this. BUT if these Bundle depends on a Locale (not in my case), its only good practic in a requestScoped Beans. in my case, it causes serialization Problems, because i declare it in an ApplicationScoped Bean, then i inject this Bean in other SessionScoped beans, which must be serializable. so all attributes (ResourceBundle included) should be serialized, and here is the Problem! – Rami.Q Jul 15 '15 at 18:10