Site Sponsors:
Java Serialization: Understanding the 'Transient' Keyword 
Created for the benefit of a class we are teaching this week.

I thought we might share the results with everyone else.

Of course, the first thing to remember is that - in order to avoid R&D problems when rolling most objects - that most of us will want to explicitly use a serialVersionUID:

private final static long serialVersionUID = 101L;


Disjoint Usage


Next, here is what happens when we use the transient keyword on unrelated classes:


package com.research;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class Controller {

public static class UserData01
implements Serializable {
private static final long serialVersionUID = 1L;
public String sName = this.getClass().getName();
public String sPassword = "Default_Password";
}

public static class UserData02
implements Serializable {
private static final long serialVersionUID = 2L;
public String sName = this.getClass().getName();
public transient String sPassword = "Default Password";
}

public static String FILE_NAME = "output.ser";

public static void main(String[] args)
throws IOException, ClassNotFoundException {

// STEP: Create stream & save the data
FileOutputStream fos = new FileOutputStream(FILE_NAME);
BufferedOutputStream bos = new BufferedOutputStream(fos);
ObjectOutputStream oos = new ObjectOutputStream(bos);
UserData01 refA = new UserData01();
refA.sPassword = "zPassword";
Report("PRE Solid - 01", refA);
oos.writeObject(refA);
UserData02 refB = new UserData02();
refB.sPassword = "zPassword";
Report("PRE Transient - 02", refB);
oos.writeObject(refB);
oos.flush();
oos.close();

// STEP: Create stream & read the data
FileInputStream fis = new FileInputStream(FILE_NAME);
ObjectInputStream ois = new ObjectInputStream(fis);
UserData01 ref1 = (UserData01) ois.readObject();
Report("POST Solid - 01", ref1);
UserData02 ref2 = (UserData02) ois.readObject();
Report("POST Transient - 02", ref2);
ois.close();
}

private static void Report(String sPrefix, UserData01 ref) {
System.out.printf("=== %s ===\n", sPrefix);
System.out.println(ref.sName);
System.out.println(ref.sPassword);
System.out.println("=====");
}

private static void Report(String sPrefix, UserData02 ref) {
System.out.printf("=== %s ===\n", sPrefix);
System.out.println(ref.sName);
System.out.println(ref.sPassword);
System.out.println("=====");
}
}


The code pretty much says it all - simply focus on where that transient keyword shows-up in the UserData02 class. Note that anything marked as being transient is never saved to the stream:


=== PRE Solid - 01 ===
com.research.UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.UserData02
zPassword
=====
=== POST Solid - 01 ===
com.research.UserData01
zPassword
=====
=== POST Transient - 02 ===
com.research.UserData02
null
=====


Witness that a null showed-up where the string would otherwise have been, despite any default assignment. Nothing unexpected there.

Transient Parent


What happens whenever our parent class has a attribute that is marked transient, is just as predictable:


public static class UserData01 implements Serializable {
private static final long serialVersionUID = 1L;
public String sName = this.getClass().getName();
public transient String sPassword = "Default_Password";
}

public static class UserData02
extends UserData01 implements Serializable {
private static final long serialVersionUID = 2L;
public String sPassword = "Default Password";
}


-That null just trades places:


=== PRE Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.Controller$UserData02
zPassword
=====
=== POST Solid - 01 ===
com.research.Controller$UserData01
null
=====
=== POST Transient - 02 ===
com.research.Controller$UserData02
zPassword
=====


Transient Children


Finally, and also just as expected, the null migrates when a child starts messin' with transient. The null follows the keyword:


=== PRE Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.Controller$UserData02
zPassword
=====
=== POST Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== POST Transient - 02 ===
com.research.Controller$UserData02
null
=====



Polymorphic Surprise!


But here is some fun: If we UPCAST to our base type, something strange happens - thru the miracle of Java Polymorphism (?), than NULL will go-away.

Doubtfull? Then just comment out the child-printer:

/*
private static void Report(String sPrefix, UserData02 ref) {
System.out.printf("=== %s ===\n", sPrefix);
System.out.println(ref.sName);
System.out.println(ref.sPassword);
System.out.println("=====");
}*/


After re-running the previous 'transient child' scenario, the results become a surprising:


=== PRE Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.Controller$UserData02
Default_Password
=====
=== POST Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== POST Transient - 02 ===
com.research.Controller$UserData02
Default_Password
=====


Interestingly enough, our newly-missing null has nothing to do with the transient keyword here. To prove it, simply remove the same from the child class, and the result will look the same.

Conclusion


Hence whilst our have member functions operate properly during the UP casting operation, our member ATTRIBUTES will do nothing of the sort. 'Kinda reminds me of the C/C++ VTABLE.

So perhaps the moral of the story is to always protect + wrapper class attributes with 'getters and 'setters. --Either way, this new nano-morphic observation has little to do with the transient parent and / or child attributes. --It is just plain good-'ol OO.

Enjoy,

-Rn

p.s. Just to complete the truth-table, here is what happens when we put that transient keyword into the parent, but have none in the child:


public static class UserData01 implements Serializable {
private static final long serialVersionUID = 1L;
public String sName = this.getClass().getName();
public transient String sPassword = "Default_Password";
}

public static class UserData02
extends UserData01 implements Serializable {
private static final long serialVersionUID = 2L;
public String sPassword = "Default Password";
}

=== PRE Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.Controller$UserData02
Default_Password
=====
=== POST Solid - 01 ===
com.research.Controller$UserData01
null
=====
=== POST Transient - 02 ===
com.research.Controller$UserData02
null
=====


Of course, after restoring our polymorphic Report()er for the child, once again we will see:

=== PRE Solid - 01 ===
com.research.Controller$UserData01
zPassword
=====
=== PRE Transient - 02 ===
com.research.Controller$UserData02
zPassword
=====
=== POST Solid - 01 ===
com.research.Controller$UserData01
null
=====
=== POST Transient - 02 ===
com.research.Controller$UserData02
zPassword
=====

-Almost interesting... wot?

=)

[ add comment ] ( 2008 views )   |  permalink
An Interview with a Saint & Mighty Maxims 
Here is a free copy of my 15th book: Known as "An Interview with a Saint", this 150 page read is enjoying 5-Star reviews on Amazon.com.

I also penned a book designed to help make our day a little brighter. If you have $2 in change, then you can toss the coins about your domicile to let Mighty Maxims pick out a daily inspiration for you.

Like my open-source projects, the more folks like 'em, them more time I spend creating similar content.

Enjoy!

-Rn



[ add comment ] ( 1749 views )   |  permalink  |  related link

<<First <Back | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | Next> Last>>