<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearch/1.1/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0' gd:etag='W/&quot;DU4MQ3w-cSp7ImA9WhFbF00.&quot;'><id>tag:blogger.com,1999:blog-14617135</id><updated>2013-09-09T11:56:22.259+05:30</updated><category term='JavaMail'/><category term='Java'/><category term='Serialization'/><title>Bits &amp; Bytes</title><subtitle type='html'>My learnings</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://blog.suryachaitanya.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14617135/posts/default?redirect=false&amp;v=2'/><link rel='alternate' type='text/html' href='http://blog.suryachaitanya.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Surya Chaitanya Tamada</name><uri>http://www.blogger.com/profile/14424718086936885519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry gd:etag='W/&quot;C0QGSH07eip7ImA9WxRbGUg.&quot;'><id>tag:blogger.com,1999:blog-14617135.post-8167250728824797721</id><published>2008-05-21T14:00:00.015+05:30</published><updated>2008-12-11T04:52:09.302+05:30</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2008-12-11T04:52:09.302+05:30</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='JavaMail'/><title>Order of BodyPart in Java Mail</title><content type='html'>I always had confusion on how to send both text and html with images content in single mail, so that all the mail clients which can render html will show html content and others which cannot render HTML will show the text content.

&lt;span class="fullpost"&gt;

&lt;br&gt;&lt;br&gt;
While sending any mail, the content-type of the mail is very important. Every content to be sent is attached to the MimeMessage as a BodyPart with proper Content type. i.e if we send a simple Text mail, content type would be text/plain, for a HTML mail it would be text/html. similarly if we send a HTML mail with embedded images, it would be multipart/relative message with each part specifying its content type.&lt;br&gt;&lt;br&gt;

When coming to sending both text and html content along with embedded messages ( will be referred as &lt;tt&gt;TEXT-HTML images embedded mail&lt;/tt&gt; herewith ), its gets bit complex, which i want to discuss here. The order in which these BodyParts are attached to the MimeMessage is very important so that message gets rendered properly in all mail clients.&lt;br&gt;&lt;br&gt;

First we will look at creating the various body parts needed in sending a &lt;tt&gt;TEXT-HTML images embedded mail&lt;/tt&gt;.&lt;br&gt;&lt;br&gt;
 
&lt;pre class="jsccJAVA"&gt;  
    private BodyPart createTextBody(File textContentFile)
            throws MessagingException, IOException
    {
        StringBuffer contentBuffer = new StringBuffer();

        BufferedReader reader = null;
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(textContentFile);
            reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));
            String content;
            while ((content = reader.readLine()) != null) {
                contentBuffer.append(content);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (stream != null) {
                stream.close();
            }
        }

        BodyPart textMessageBodyPart = new MimeBodyPart();
        textMessageBodyPart.setContent(contentBuffer.toString(), "text/plain; charset=UTF-8");
        return textMessageBodyPart;
    }

    private BodyPart createHtmlBody(File htmlContentFile)
            throws MessagingException, IOException
    {
        StringBuffer contentBuffer = new StringBuffer();

        BufferedReader reader = null;
        FileInputStream stream = null;
        try {
            stream = new FileInputStream(htmlContentFile);
            reader = new BufferedReader(new InputStreamReader(stream, "utf-8"));
            String content;
            while ((content = reader.readLine()) != null) {
                contentBuffer.append(content);
            }
        } finally {
            if (reader != null) {
                reader.close();
            }
            if (stream != null) {
                stream.close();
            }
        }

        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setContent(contentBuffer.toString(), "text/html; charset=UTF-8");

        return messageBodyPart;
    }

    private BodyPart createImagePart(File imagePath, String cid)
            throws MessagingException
    {
        BodyPart messageBodyPart = new MimeBodyPart();
        messageBodyPart.setDataHandler(new DataHandler(new FileDataSource(imagePath)));
        messageBodyPart.setHeader("Content-ID", "&lt;" + cid + "&gt;");
        messageBodyPart.setDisposition("inline");

        return messageBodyPart;
    }
&lt;/pre&gt;

Attaching these contents to mimemessage, we have two options (actually its only one option, as other option will not render the email properly in some mail clients, which is the reason for this entire article)&lt;br&gt;&lt;br&gt;

Option one:&lt;br&gt;
    Create a multipart/alternative message, with two parts&lt;br&gt;
&lt;ul&gt;
        &lt;li&gt;  First part having the TextBodyPart.&lt;br&gt;
        &lt;li&gt; Second part will be a multipart/related message, again with two parts&lt;br&gt;
        &lt;ul&gt;
                &lt;li&gt; First part will have HTMLBodyPart &lt;br&gt;
                &lt;li&gt; Second part will be the ImageBodyPart to be Embedded which were used in HTMLBodyPart
        &lt;/ul&gt;
&lt;/ul&gt;&lt;br&gt;

How on arriving at the above multipart subtypes is beyond the scope of this entry.  Interested users can get needed information &lt;a href="http://en.wikipedia.org/wiki/MIME"&gt;here&lt;/a&gt;&lt;br&gt;&lt;br&gt;

Translating the above steps into code:&lt;br&gt;&lt;br&gt;

&lt;pre class="jsccJAVA"&gt;
    private void updateContentOptionOne(MimeMessage mimeMessage, File textContentFile, 
                                        File htmlContentFile, File imagePath)
            throws MessagingException, IOException
    {
        MimeMultipart outerPart = new MimeMultipart("alternative");

        BodyPart textBody = createTextBody(textContentFile);
        outerPart.addBodyPart(textBody);

        MimeMultipart innerPart = new MimeMultipart("related");
        innerPart.addBodyPart(createHtmlBody(htmlContentFile));
        innerPart.addBodyPart(createImagePart(imagePath, imagePath.getName()));

        BodyPart relatedPart = new MimeBodyPart();
        relatedPart.setContent(innerPart);
        outerPart.addBodyPart(relatedPart);

        mimeMessage.setContent(outerPart);
    }
&lt;/pre&gt;

If the above sent content is checked in Yahoo! Mail, Gmail or on offline web clients like Thnderbird, Evolution everything looks fine. but if you use a webmail Client which displays only textContent like SquirrelMail, you will see only the text content. and there would be no option to view the html content as shown below:&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_2uC9kHwwhL8/SDOxSJ7x0GI/AAAAAAAAB4s/ZvHmMgxqUPg/s1600-h/OptionOne.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_2uC9kHwwhL8/SDOxSJ7x0GI/AAAAAAAAB4s/ZvHmMgxqUPg/s320/OptionOne.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5202696920005464162" /&gt;&lt;/a&gt;

Coming to the Option two:&lt;br&gt;&lt;br&gt;

Create a multipart/related message, with two parts     &lt;br&gt;  
&lt;ul&gt;
        &lt;li&gt;  First part will be a multipart/alternative message, again with two parts&lt;br&gt;
        &lt;ul&gt;
                &lt;li&gt; First part will have TextBodyPart&lt;br&gt;  
                &lt;li&gt; Second part having the HTMLBodyPart&lt;br&gt;
        &lt;/ul&gt;
        &lt;li&gt; Second part will be the ImageBodyPart to be Embedded which are used in HTMLBodyPart
&lt;/ul&gt;&lt;br&gt;

Translating the above steps into code:&lt;br&gt;&lt;br&gt;

&lt;pre class="jsccJAVA"&gt;
    private void updateContentOptionTwo(MimeMessage mimeMessage, File textContentFile, 
                                        File htmlContentFile, File imagePath)
            throws MessagingException, IOException
    {
        MimeMultipart outerPart = new MimeMultipart("related");

        MimeMultipart innerPart = new MimeMultipart("alternative");
        innerPart.addBodyPart(createTextBody(textContentFile));
        innerPart.addBodyPart(createHtmlBody(htmlContentFile));

        BodyPart alternativePart = new MimeBodyPart();
        alternativePart.setContent(innerPart);
        outerPart.addBodyPart(alternativePart);

        BodyPart imagePart = createImagePart(imagePath, imagePath.getName());
        outerPart.addBodyPart(imagePart);

        mimeMessage.setContent(outerPart);
    }
&lt;/pre&gt;

Now if you check the mail sent in SquirrelMail WebMailClient, it looks like below, text content with html mail as an attachment.&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2uC9kHwwhL8/SDOxSZ7x0HI/AAAAAAAAB40/tCsEobWceYk/s1600-h/OptionTwo.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_2uC9kHwwhL8/SDOxSZ7x0HI/AAAAAAAAB40/tCsEobWceYk/s320/OptionTwo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5202696924300431474" /&gt;&lt;/a&gt;

Clicking on the attachment will show the HTML content.&lt;br&gt;&lt;br&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_2uC9kHwwhL8/SDOxSZ7x0II/AAAAAAAAB48/hwDRmI8XQek/s1600-h/HtmlContent.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_2uC9kHwwhL8/SDOxSZ7x0II/AAAAAAAAB48/hwDRmI8XQek/s320/HtmlContent.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5202696924300431490" /&gt;&lt;/a&gt;

Again in this option (Option Two), the order in which we attach the alternative messages are important, as in some offline mail clients like Thunderbird (tested on version 2.0.0.14), it picks up the last alternative message in the list of available alternatives it can render. So if we attach the HtmlBodypart before the TextBodyPart, we would be seeing the Text content, though Thunderbird can render the HTML content attached.&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;
&lt;img src="http://www.suryachaitanya.com/cab_extract.png"&gt;&lt;img&gt;  &lt;a href="http://www.suryachaitanya.com/mail.jar"&gt;Download Source&lt;/a&gt;

&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.suryachaitanya.com/feeds/8167250728824797721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14617135&amp;postID=8167250728824797721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14617135/posts/default/8167250728824797721?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14617135/posts/default/8167250728824797721?v=2'/><link rel='alternate' type='text/html' href='http://blog.suryachaitanya.com/2008/05/java-mail-order-of-bodypart-important.html' title='Order of BodyPart in Java Mail'/><author><name>Surya Chaitanya Tamada</name><uri>http://www.blogger.com/profile/14424718086936885519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_2uC9kHwwhL8/SDOxSJ7x0GI/AAAAAAAAB4s/ZvHmMgxqUPg/s72-c/OptionOne.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry gd:etag='W/&quot;DEMAQX0zfSp7ImA9WxdbEU0.&quot;'><id>tag:blogger.com,1999:blog-14617135.post-6124909609778080616</id><published>2007-05-15T10:34:00.002+05:30</published><updated>2008-08-07T16:24:00.385+05:30</updated><app:edited xmlns:app='http://www.w3.org/2007/app'>2008-08-07T16:24:00.385+05:30</app:edited><category scheme='http://www.blogger.com/atom/ns#' term='Serialization'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title>Java Object Serialization</title><content type='html'>Java Object Serialization is often confused subject for me. I first learned about them when i was having my Java training. Then when i got to use this for persisting session information for our container, i read more on this and went through the SUN's JDK source. While going though i found something interesting, which lead to think that Java serialization can break in some cases. I may be wrong, but again i want users who read this blog to explain where did i go wrong.

&lt;span class="fullpost"&gt;
let us try first with an example.

ClassA has a writeReplace which replaces itself with instance of ClassB. 

&lt;pre class="jsccJAVA"&gt;
public class ClassA
        implements Serializable
{
    private String classAData;

    public ClassA(String classAData)
    {
        this.classAData = classAData;
    }

    public String getClassAData()
    {
        return classAData;
    }

    public Object writeReplace()
    {
        System.out.println("ClassA.WriteReplace [" + this + "]");
        return new ClassB(classAData);
    }

    public Object readResolve()
    {
        System.out.println("ClassA.readResolve --&gt; Nothing to do");
        return this;
    }

    public String toString()
    {
        return "Class A: " + classAData;
    }
}
&lt;/pre&gt;

and ClassB does vice-versa i.e has readResolve which replaces itself with instance of ClassA. 

&lt;pre class="jsccJAVA"&gt;
public class ClassB
        implements Serializable
{
    private String classBData;

    public ClassB(String classBData)
    {
        this.classBData = classBData;
    }

    public String getClassBData()
    {
        return classBData;
    }

    public Object writeReplace()
    {
        System.out.println("ClassB.writeReplace --&gt;  Nothing to do");
        return this;
    }

    public Object readResolve()
    {
        System.out.println("ClassB.readResolve [" + this + "]");
        return new ClassA(classBData);
    }

    public String toString()
    {
        return "Class B: " + classBData;
    }
}
&lt;/pre&gt;

ClassC has a writeObject and readObject where it writes/reads its variable 'classCData' into/from object stream respectively.

&lt;pre class="jsccJAVA"&gt;
public class ClassC
        implements Serializable
{
    private String classCData;

    public ClassC(String classCData)
    {
        this.classCData = classCData;
    }

    public String getClassCData()
    {
        return classCData;
    }

    private void writeObject(ObjectOutputStream out) throws IOException
    {
        System.out.println("ClassC.writeObject");
        out.writeObject("SU:" + classCData);
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        System.out.println("ClassC.readObject");
        String str = (String) in.readObject();
        classCData = str.substring(3);
    }

    public Object writeReplace()
    {
        System.out.println("ClassC.writeReplace --&gt; Nothing to do");
        return this;
    }

    public Object readResolve()
    {
        System.out.println("ClassC.readResolve --&gt; Nothing to do");
        return this;
    }

    public String toString()
    {
        return "Class C: " + classCData;
    }
}
&lt;/pre&gt;

CustomObjectInputStream has a resolveObject where it replaces an Object of ClassC with ClassB

&lt;pre class="jsccJAVA"&gt;
public class CustomObjectInputStream
        extends ObjectInputStream
{
    public CustomObjectInputStream(InputStream in)
            throws IOException
    {
        super(in);
        enableResolveObject(true);
    }

    protected Object resolveObject(Object obj) throws IOException
    {
        if (obj instanceof ClassA || obj instanceof ClassB || obj instanceof ClassC) {
            System.out.println("CustomObjectInputStream.resolveObject [" + obj + "]");
        }
        if (obj instanceof ClassC) {
            return new ClassB(((ClassC) obj).getClassCData());
        }
        return obj;
    }
}
&lt;/pre&gt;

and CustomObjectOutputStream does vice versa i.e has a replaceObject where it replaces a an Object of ClassB with ClassC

&lt;pre class="jsccJAVA"&gt;
public class CustomObjectOutputStream
        extends ObjectOutputStream
{
    public CustomObjectOutputStream(OutputStream out)
            throws IOException
    {
        super(out);
        enableReplaceObject(true);
    }

    protected Object replaceObject(Object obj) throws IOException
    {
        if (obj instanceof ClassA || obj instanceof ClassB || obj instanceof ClassC) {
            System.out.println("CustomObjectOutputStream.replaceObject [" + obj + "]");
        }
        if (obj instanceof ClassB) {
            return new ClassC(((ClassB) obj).getClassBData());
        }
        return obj;
    }
}
&lt;/pre&gt;

Now my Main class looks like below:

&lt;pre class="jsccJAVA"&gt;
public class Main
{
    public static void main(String[] args) throws IOException, ClassNotFoundException
    {
        ByteArrayOutputStream byteOutStream = new ByteArrayOutputStream();
        CustomObjectOutputStream objOutStream = new CustomObjectOutputStream(byteOutStream);

        ClassA obj = new ClassA("Test***String");
        objOutStream.writeObject(obj);
        objOutStream.flush();
        byte[] data = byteOutStream.toByteArray();


        ByteArrayInputStream byteInStream = new ByteArrayInputStream(data);
        CustomObjectInputStream objInStream = new CustomObjectInputStream(byteInStream);
        Object reCreatedObj = objInStream.readObject();
        if (reCreatedObj instanceof ClassA) {
            System.out.println("Class is correct");
            if (obj.getClassAData().equals(((ClassA) reCreatedObj).getClassAData())) {
                System.out.println("data also matched");
            } else {
                System.out.println("data Didnt matched");
            }
        } else {
            System.out.println("Read and write DataObject Failed. returned Object [" + reCreatedObj + "]");
        }
    }
}
&lt;/pre&gt;

I expected output to be like: &lt;br&gt;
&lt;span style="font-style:italic;"&gt;&lt;pre&gt;ClassA.WriteReplace [Class A: Test***String]
ClassB.writeReplace --&gt;  Nothing to do
CustomObjectOutputStream.replaceObject [Class B: Test***String]
ClassC.writeObject
ClassC.readObject
CustomObjectInputStream.resolveObject [Class C: Test***String]
ClassB.readResolve [Class B: Test***String]
ClassA.readResolve --&gt; Nothing to do
Class is correct
data also matched&lt;/pre&gt;&lt;/span&gt;

but the output is  &lt;br&gt;
&lt;span style="font-style:italic;"&gt;&lt;pre&gt;ClassA.WriteReplace [Class A: Test***String]
ClassB.writeReplace --&gt;  Nothing to do
CustomObjectOutputStream.replaceObject [Class B: Test***String]
ClassC.writeObject
ClassC.readObject
ClassC.readResolve --&gt; Nothing to do
CustomObjectInputStream.resolveObject [Class C: Test***String]
Read and write DataObject Failed. returned Object [Class B: Test***String]&lt;/pre&gt;&lt;/span&gt;

Now going through the ObjectOutputStream and ObjectInputStream Source Code you will find the following sequence followed in persisting and resolving an Object.

&lt;span style="font-weight:bold;"&gt;While converting an Object into a series of bytes:&lt;/span&gt;
&lt;ol TYPE="1" START="1"&gt;
&lt;li&gt; Check whether ObjectOutputStream is created using overridden default constructor. if yes, just give callback to writeObjectOverride(Object obj) and return. (In our case, CustomObjectOutputStream doesn't override default Constructor. so go to step 2)
&lt;li&gt; If not, Check whether the Object to be persisted has a writeReplace method overridden. If yes, replace the incoming Object with returned Object. (in our case, ClassA has overridden WriteReplace. After this method invocation, the object to be persisted is Object of type ClassB). &lt;span style="font-weight:bold;"&gt;Repeat step 2 if the returned Object has a writeReplace(), until an object returned doesn't override writeReplace().&lt;/span&gt;
&lt;li&gt; Then Check whether ObjectOuputStream has a replaceObject(Object obj) method. If yes, pass the above returned Object and get the new Object to be persisted. This method would be invoked only when the ObjectOutputStream sub class, sets the enableReplaceObject(boolean) to true. (enableReplaceObject is set for our CustomObjectOutputStream. So invoking above method with object of type ClassB, returns Object of type ClassC)
&lt;li&gt; Then check whether the replaced object from above method implements Serializable/Externalizable. if not, throw InvalidClassException. (ClassC implements Serializable)
&lt;li&gt; else, write the class Description first.  and then if above object extends Serializable invoke writeObject() if defined or else persist all the primitive data. Or if above Object extends Externalizable invoke writeExternal. (Object of type ClassC is converted into bytes using writeObject).
&lt;/ol&gt;

&lt;span style="font-weight:bold;"&gt;and while recreating, with above created bytes,&lt;/span&gt;

&lt;ol&gt;
&lt;li&gt; Check whether ObjectInputStream is created using overridden default constructor. If yes, give call Back to readObjectOverride(), and return. (In our case, CustomObjectInputStream doesn't override defaultConstructor. so go to step 2)
&lt;li&gt; If not, read the classDescription First. and if the constructed class instance is not of type Serializable the data is corrupted, so throw a InvalidClassException. (Object of ClassC is created)
&lt;li&gt; Then check whether class implements Externalizable/Serializable and invoke readExternal or readObject() respectively and get an instance. (as ClassC implements Serializable invoke readObject()) 
&lt;li&gt; Then invoke the readResolve method if defined on the above resolve method. (now here, ClassC readResolve() method is invoked which doesn't do anything). &lt;span style="font-weight:bold;"&gt;This is not a recursive call unlike writeReplace().&lt;/span&gt;
&lt;li&gt; Then check whether the ObjectInputStream has a resolveObject. If yes, pass this Object and return the returned Object as the Object constructed from persisted bytes. (as ObjectInputStream has a resolveObject method defined, we pass Object of type ClassC, so returned Object would be of type ClassB).
&lt;/ol&gt;

So when we compare both persisted Object (type ClassA) and recreated Object (type ClassB) they don't match. If SUN's Java Serialization has been written in such a way that above sequences 4 and 5 are interchanged, it would have been exactly as i have expected.

Now i don't know the reason why sun Java serialization is implemented in above fashion. if anyone there know please update me by putting your comments.

&lt;span style="font-weight:bold;"&gt;&lt;span style="font-style:italic;"&gt;PS: tried above example on SUN JDK 1.5.0_10.&lt;/span&gt;&lt;/span&gt;

&lt;/span&gt;</content><link rel='replies' type='application/atom+xml' href='http://blog.suryachaitanya.com/feeds/6124909609778080616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14617135&amp;postID=6124909609778080616' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14617135/posts/default/6124909609778080616?v=2'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14617135/posts/default/6124909609778080616?v=2'/><link rel='alternate' type='text/html' href='http://blog.suryachaitanya.com/2007/05/java-object-serialization-is-often_15.html' title='Java Object Serialization'/><author><name>Surya Chaitanya Tamada</name><uri>http://www.blogger.com/profile/14424718086936885519</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>