Skip to main content

Moonlight Thoughts

Posted by lamine_ba on May 21, 2011 at 1:32 PM PDT

In computer science, in the context of data storage and transmission, serialization is the process of converting a data structure or object into a format that can be stored and "resurrected" later in the same or another computer environment. Java provides automatic serialization which requires that the object be marked by implementing the java.io.Serializable interface. Implementing the interface marks the class as "okay to serialize. There are no serialization methods defined on the Serializable interface, but a serializable class can optionally define methods with certain special names and signatures that if defined, will be called as part of the serialization/deserialization process. The language also allows the developer to override the serialization process more thoroughly by implementing another interface, the Externalizable interface, which includes two special methods that are used to save and restore the object's state.

Wikipedia

Introduction

Last week, while letting a beautiful moon shine, my friend Bob and I were discussing. We didn't find in that evening, any interesting subject other than my previous blog post, which was if you remember, the writing expression of a skeleton. The skeleton of a solution. The solution of how to "implement a cascading dropdown using the JSF framework". And today, coming again with the tremendous desire to share, my friend Bob and I are very pleased to give you a replay of that conversation so you can touch our moonlight thoughts. Furthermore, when all things are said and done, what else from an ending whisper than to fall into a deep silence and let the story begin...

The Conversation

Me: Hey Bob! Have you read my last blog post on java.net?

Bob: Which one? the one talking about how to implement a cascading dropdown with JSF 2?

Me : Yes this one. In the case you read it, did you have your question answered?

Bob: I'm really sorry, I can't remember what it was. Could you be more accurate?

Me: Of course, bob. Last time, you were asking me what was the correlation between an UISelectOne component and a bean put in any scope
after having asked you why I was getting this validation error.

Bob: Oh yeah! I can still remember this one and like I often say to my coworkers, the solution comes always when the question is better asked.
In the way it is designed, the validation of the value of an UISelectOne or an UISelectMany component will always fail when
having your bean put in the request scope.

  1. public class UISelectOne extends UIInput {
  2.  
  3. protected void validateValue(FacesContext context, Object value) {
  4.  
  5.         // Skip validation if it is not necessary
  6.         super.validateValue(context, value);
  7.  
  8.         if (!isValid() || (value == null)) {
  9.             return;
  10.         }
  11.  
  12.         // Ensure that the value matches one of the available options
  13.         boolean found = SelectUtils.matchValue(getFacesContext(),
  14.                                                this,
  15.                                                value,
  16.                                                new SelectItemsIterator(context, this),
  17.                                                getConverter());
  18.  
  19.         boolean isNoSelection = SelectUtils.valueIsNoSelectionOption(getFacesContext(),
  20.                                                this,
  21.                                                value,
  22.                                                new SelectItemsIterator(context, this),
  23.                                                getConverter());
  24.  
  25.         // Enqueue an error message if an invalid value was specified
  26.         if ((!found) ||
  27.             (isRequired() && isNoSelection)) {
  28.             FacesMessage message =
  29.                 MessageFactory.getMessage(context, INVALID_MESSAGE_ID,
  30.                      MessageFactory.getLabel(context, this));
  31.             context.addMessage(getClientId(context), message);
  32.             setValid(false);
  33.         }  
  34.     }
  35. }

JSF like any logical system is unable to validate a value against a list of values which becomes unavailable at the end of the request.Your only advice could be to keep the state and that is exactly what it does when the bean is put in the view scope.

Me: But bob, do you see any reason why the value is not validated against the tree? Aren't the set of valid values simply children of the UISelectOne?

Bob: Yes they are but let me show you where the problem is. No one can do a value comparison against the UISelectItems component because we only save the value expression which means a regeneration of the data model through a costly EL evaluation at any phase we need the data. One must now question why we cannot replace in the tree an UISelectItems by a list of UISelectItem? Having not myself the answer, I leave it to your appreciation.

Me: And I'll forward it to Ed Burns. Now let's come back to the ViewScope. As you state, the only advice we can give to JSF is to keep the state and all of this reminds me the UISaveState component from MyFaces Tomahawk project. Does it work the same?

Bob: The Tomahawk t:saveState tag provides an alternative "view" scope. It allows objects to be associated with the current JSF view, so that they are kept alive while the user stays on the same view, but are automatically discarded when the user moves to another view. Note that the t:saveState tag does require that all the objects it stores are Serializable or implement the JSF StateHolder interface.When JSF is configured to use "client-side-state-saving"

  1. <context-param>
  2. <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  3. <param-value>client</param-value>
  4. </context-param>

then objects in "view" scope are automatically sent to the browser along with the rest of the JSF view state.However of course the network bandwidth needed does increase as the view-scoped objects must be transferred back and forth on each request. In the other hand, when JSF is configured to use "server-side-state-saving"

  1. <context-param>
  2. <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  3. <param-value>server</param-value>
  4. </context-param>

then objects in "view" scope are automatically stored in the HttpSession along with the rest of the JSF view state.

Me : Having now the proof that we are talking about the same concept, it is self evident that I did a mistake in my previous blog post. If state saving means really Serialization, how JSF could save the state of a bean and its members if they don't implement the Serializable interface?

  1. @ManagedBean
  2. @ViewScoped
  3. public class Bean implements Serializable {
  4.  
  5. }

Bob: Very good question. The ViewScope is attached to the UIViewRoot and when the UIViewRoot state is saved, it may be serialized by the StateManager implementation.

  1. public class UIViewRoot extends UIComponentBase implements UniqueIdVendor {
  2.  
  3. private Map<String, Object> viewScope = null;
  4.  
  5. public Map<String, Object> getViewMap() {
  6.  
  7.     return getViewMap(true);      
  8. }
  9.  
  10. public Map<String, Object> getViewMap(boolean create) {
  11.  
  12.         if (create && viewScope == null) {
  13.             viewScope = new ViewMap(getFacesContext().getApplication().getProjectStage());
  14.             getFacesContext().getApplication()
  15.                   .publishEvent(getFacesContext(),
  16.                                 PostConstructViewMapEvent.class,
  17.                                 this);
  18.         }
  19.         return viewScope;  
  20. }
  21.  
  22. }

Me: Shame on my reviewer! But the real truth is that I haven't tried the solution myself until yesterday and guess what, I got this nasty java.io.NotSerializableException error

Bob: ooh! I'm really sorry for the frustration but did the CDI @Inject annotation work for you? What were your dependencies? SeamFaces or Myfaces CODI? And by the way, aren't these annotations that share the same unqualified name confusing to you?

Me: Yes from the perspective of a beginner, they are. I use SeamFaces to enable the CDI injection on my bean

Bob: and did you replace @ManagedBean by @Named ?

Me: of course, after having got a traumatic NullPointerException. You have to use the @Named annotation so that CDI is used instead of JSF but it is really intriguing why we cannot automatically map JSF managed bean annotations to CDI annotations at startup. It is high time to think about what to do with JSF's own managed bean mechanism.

Bob: Yes I agree and like it is stated in its goal, JSF is a user interface framework for Java Web applications designed to significantly ease the burden of writing and maintaining applications that run on a Java application server and render their UIs back to a target client.

Me: So if I'm following you, JSF must now focus on the UI, delegate the DI task and deprecate its managed bean mechanism.

Bob: You already know my position about this debate so why talking more about it. I would rather talk about why haven't you packaged your solution into a reusable unit we can download, install and try.

Me: Oh bob! I wish I could but this feature is currently under prototyping in JSF 2.2. We call it Support for modular, reusable, fragments of a web application. My apologies for the time wasted and for the copy and paste. But believe me soon all this pain will belong to the past......

Related Topics >>