Letters to the editor
By:





Object Persistence
'Flatten your objects'
Todd M. Greanier

Isn't there a better way to serialize a Date object?

Todd,

I must admit, I found the first example in this article so contrived and mysterious that I gave up on reading it. Why? Because the so-called PersistentTime class simply wraps a class that is already Serializable. You could have illustrated the process by working directly with a Date object and pointing out that Date implements Serializable (in 1.2, at least). Instead, you left the reader with the impression that your way was the only way to serialize a Date object, conveniently brushing over the induction problem of serializing the object's contents.

A much better example, perhaps, would have been to make the class you defined in the example a wrapper for a couple of primitive types, say an int X, Y pair. You could have then answered the question of how the contents become serialized by simply saying "the system knows how to (de)serialize the primitive types."

I'm sure I'll go back to the article, but it is a shame to see it start off in such an illogical fashion.

Pete

Pete,

I see your point about my PersistentTime example leading readers to believe this is the only way to serialize a Date object. As you pointed out, Date is already Serializable.

However, the purpose of this example is not to reveal the inner workings of the serialization process, but to demonstrate how to perform serialization in Java. I chose Date as a member variable because it is Serializable. I explore this further in the article when I discuss the use of transient as a keyword.

While the opening example is admittedly a bit contrived, I have used it for years to explain the serialization process to beginners.

I appreciate your incisiveness.

Todd Greanier :

What about saving event listeners?

Todd,

I depend on serialization, but I've yet to save an object's state. Thanks to you, I now know how.

One pitfall I encountered was saving event listeners. Given the importance of event models in bean production/utilization, I think it would be useful to warn about this particular problem. When implementing a reusable object that publishes some events, you can generally assume its listeners aren't serializable. Also, you probably don't want to store a listener's relation anyway. This leads to the following rules for serializable event sources:

  1. Declare the listener container transient:



        protected transient Vector m_listeners=null;

  2. Do not construct listener container in constructor, but on demand:



        public add<Event>Listener(<Event>Listener l)
        {
           if (m_listeners==null) m_listeners=new Vector();
           if (!m_listeners.contains(l)) m_listeners.addElement(l);
        }

        public remove<Event>Listener(<Event>Listener l)
        {
           if (m_listeners==null) return;
           m_listeners.removeElement(l);
        }

        protected void fire(<Event> e)
        {
           if (m_listeners==null) return;
           synchronized(this){ .......
        }

Of course, testing the existence of a container constructed in readObject can be excluded, but that is a question of taste.

I observed this pattern after I had serialized some of my own event sources and obtained a null pointer exception from deserialized objects -- no vector -- or suddenly received cannot serialize (because now a listener cannot). I don't think I'm the first to fall into this trap!

Arne

Arne,

That is excellent advice. You are certainly not the first to have this problem. The serializing of event listeners, usually done with an IDE, is often completed in JavaBeans. The IDE generally creates adapter listeners that are really saved, and are serializable.

I am sure others have had this problem, and your advice could save them hours of debugging.

Todd Greanier :

How do you solve the versioning problem?

Todd,

Since I used Serialization to save the object to Database, I am particularly interested in the versioning part. I used the Externalizable interface to take care of the versioning problem. Because I have full control of each field's read/write in my class, I assume it will work. Is this the correct approach to solving the versioning issue?

Do I need to place the following line in my class declaration?


static final long serialVersionUID = *******;

As long as my change is compatible and this UID remains the same, will there be a problem reading out a persisted object?

Jia

Jia,

You seem to have the correct code. All you need to do is insert that static final line and you will allow legacy serialized objects to be read, even by newer versions of the classes.

Assume you have a class called Fred, with an int called x. Create a Fred object and serialize it. Now add another field to Fred and call it an int, y. If you maintain the serialVersionUID across this change, you will be able to read in the flattened Fred object. When the stream is complete, the object will be complete. The new int y will be equal to its default, 0, in the deserialized object. The next time you write it out, the new value of y will be correct.

Todd Greanier :

Design Patterns
'HMVC: The layered pattern for developing strong client tiers'
Jason Cai, Ranjit Kapila, and Gaurav Pal

Is HMVC PAC?

Jason, Ranjit, and Gaurav,

In this article, you basically presented an already-specified design pattern called PAC (Presentation-Abstraction-Control). Overall, I don't see any difference in the two. But like PAC, HMVC will not scale well on large projects, especially with Swing or AWT 1.1 event model -- remember, you don't complete new model event delegation by propagating the event from component to component. The PAC or HMVC architecture will serve well when applied with the JavaBeans frameworks, especially BeanContext, for hooking them up with Swing- or servlet-based UIs.

TP

TP,

Thank you for your mail regarding the similarities between HMVC and PAC. We must admit we were not familiar with PAC; after receiving your email, we studied it closely in order to contrast it with HMVC.

Our conclusion is similar to yours. For the most part, PAC and HMVC discover the same design pattern. We are glad to know about this similarity, because in a way, it validates our conclusions. Both patterns are variations on the MVC theme -- they have the underlying concept of a controller hierarchy in common. In fact, HMVC might be most accurately described as a subset of PAC.

Since we observed the HMVC design pattern in our client-side Java implementations, HMVC is a more specific pattern. It merely focuses on UI; we discovered it within this scope. We recognize that it is a general design pattern and would be applicable to other object-oriented language GUIs as well. PAC is a more generic pattern that addresses all interactive software. It usually covers a hierarchical organization of the triads. PAC also addresses variations that involve no abstraction or presentation.

There are, however, a few differences between the two patterns. In HMVC, tight coupling is retained between the model and the view. When a model is updated, the controller instructs the view to refresh itself, but the view then queries the model directly instead of going through the controller. Basically, we favor tight coupling within the triad. By always using the controller as a mediator, PAC keeps the model and view loosely coupled.

The basic PAC design pattern describes that the top-level PAC agent performs all data access. HMVC suggests that in addition to data access via the top-level GUIContainerController, the models at any level can directly access the data.

To summarize, HMVC can probably be classified as a subset or variation of the PAC theme. Our approach features tight coupling within an MVC triad, as well as direct access to external data from any level, because these two components helped us scale better in our Java implementations.

On the subject of scalability, HMVC is not a solution for thin clients. As with most object-oriented designs, developers should focus primarily on isolating responsibilities to increase reusability and maintainability. HMVC introduces layers and the propagation of events -- this means more work needs to be completed. However, the added value of restricting the number of levels far outweighs the resulting overhead on the client. This design suits a control-rich (thick) client and probably runs on a reasonable platform.

Once again, thanks for your extremely insightful feedback.

Jason, Ranjit, and Gaurav :

Multithreaded Programming
'Lock on to an alternate synchronization mechanism'
Tarak Modi
Note: Reader Bill Pugh's comments were first responded to by his colleague Doug Lea -- noted in blue below. Author Tarak Modi responds to Doug's comments in his reply.

Double-check 'double-checked locking'

Tarak,

Your article states: "Double-checked locking prevents erroneous locking conditions."

But the double-checked locking idiom doesn't work in Java -- at least not in a cross-platform way. To make it work in C++, you need appropriately placed memory barriers. Because Java doesn't have memory-barrier instructions, it can't work. Doug Schmidt talks about this problem in his new book.

For more details, see slides from the JavaOne talk that Doug Lea and I gave.

More particulars are available at the Java Memory Model Webpage.

Bill Pugh

Bill and Tarak,

Actually, the code listing in question is not an example of Schmidt's double-checked idiom. It is an example of the standard-monitor idiom of surrounding "waits" with "while" loops that check conditions upon returning from wait, which is important to ensure reliable signaling.

So the underlying error was referencing Schmidt's pattern, which applies to different constructions than those used in this code.

Doug Lea

Doug,

I appreciate your response. Maybe I interpreted Doug Schmidt's pattern too broadly. The logic behind the standard-monitor, as you refer to it, and the double-checked patterns is very similar: checking a condition once before and once after acquiring a lock. Double-checking is not about the if statement and singletons, but the logic mentioned above. But that is only my opinion.

I am intrigued by Bill's statement that double-checked locking does not work in Java and would like to know more about this, with proof if possible. Such blanket statements must be made with great care. At Bill's suggestion, I also reviewed the presentation that you and he made at a JavaOne conference. It contained a statement to the effect of "even the authors of the VM specification did not understand it," which is quite bold. What exactly does that mean? How can the authors themselves not understand the specification?

I would like to thank you and Bill for taking the time to read and critique my article. Other than the issue you brought up, which does not affect the code/lock itself, I hope you enjoyed the rest of the article.

Tarak :

Java Q&A
'The world's biggest ball of string'
Tony Sintes

As the 'hello world' interns

Tony,

I am a Java beginner and a Sun certified programmer for Java 2. Please explain your answer to Question 3.

Why mention the second object at all? According to the Java Specs, every hello here will be interned at compile time, so there will be only one hello in the intern string pool.

Did I understand this correctly?

Gautam

Gautam,

You are absolutely correct. I was confused, which is why I asked for clarification from the readers. I guess I would miss this question on a test.

Let's look at the code and I will explain my thinking:


     a = "hello"
     b = "hello"
     c = new string("hello")
     d = "hello"

I knew that a and b would intern. c results in the creation of a new String object. Since it is not a simple string constant, it doesn't intern.

Now I understand that d will intern just like a and b. My confusion stemmed from the fact that when d is declared, two hello objects already exist. But because of intern rules, d will just intern to the same object as a and b.

Tony Sintes

:



This page formated for crawlers and browsers that don't support scripts and tables.
Home
EZone