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 ] ( 2095 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 ] ( 1838 views )   |  permalink  |  related link
Enumeration -v- Exception? 
From 'enums to templates, both Sun/Oracle and Microsoft continue to learn allot from C/C++. Just as certainly however, many an old C/C++ 'hand will find allot of cohesive design patterns in Java, too.

Some ideas - like separating our 'readers from our 'writers - are good. Other ideas - like omitting pointers - are bad. Finally, some ideas - like favorings exceptions over enumerators - are just plain old ugly.

Exceptions Are Evil?


Not only are exceptions ugly, but the stack & memory cost of using exceptions can often make using exceptions unnecessarily expensive, too.

Is there a better way?

Well, for a start, let's consider how far too many of us often create a customized exception:


public class Exceptional
extends Exception {
// Often nothing else goes here.
// -We only want to create a
// new name?
}


The net effect of using an exception to simply create an enumerable response - as innocent as we might imagine it to be - is to create a code and memory sand-bar; A full blown class; An object to toss-around a slowly-unwinding stack .... only to be caught elsewhere ... by what effectively amounts to an extremely inefficient switch statement:


try {
...
}
catch(Exceptional ex) {
}
catch(IOException ex) {
}
catch(Exception ex) {
}


Indeed, if all we are looking for is a way to name something like Exceptional as an intra-process communication 'flag', then why not just forget about creating any type of Throwable? Why not simply use an enumeration, instead?

Benefits of Enumerations


Ever concerned with higher performance and efficiencies, in C/C++, we have traditionally been able to turn-off things like run-time type-identification and exceptions. Those reasons alone are part of why C++ will ever be far, far more efficient than .NET or Java.

But since enumerators arrived far, far latter in Java than they did in C/C++, developers continue on with what has become a traditional use of exceptions... Even when returning a simple C/C++-style enumeration would be far, far more understandable, & efficient:


public class Alternative {
enum Exceptional {
ea_Good,
ea_Bad,
ea_Ugly
}
public Exceptional Groovy() {
return Exceptional.ea_Good;
}
}


So rather than tossing a 50-pound 'thrown' wrecking-ball around our framework, why not simply return an open-ended enumeration (i.e. we can always add more enumerated names), instead?


public void Cool() {
switch(Groovy()) {
case ea_Good:
break;
case ea_Bad:
break;
case ea_Ugly:
break;
default:
break;
}
}


Indeed, rather than working so hard to merely let a future exception slip through our hands ... and unlike that legacy try/catch block ... when using a switch, that default: tag works a lot harder than any type of finally statement. Why? Because no super-block flags need to be set:


boolean imadoofus = false;
try {
...
}
catch(Exceptional ex) {
imadoofus = true;
}
catch(IOException ex) {
imadoofus = true;
}
catch(Exception ex) {
imadoofus = true;
}
finally {
if(imadoofus) {
...
}
}


Hence we are all learning.

Such noted however, perhaps we all need to keep-up with the ripple-effects whenever a standard is updated. Indeed, actually applying what-we-borrow from other camps often has some very favorable effects upon our legacy code-creation practices. In the case of preferring a single enumeration over a plethora of gratuitous exception class-creations, reserving the creation of custom Exceptions for managing far less-recoverable Error-type of 'throwables, may just be one more nice practice to get used to.

Return Result Paradigm Shift


Lastly, while most of us are in the habit of returning types from member functions (i.e. Java has no pointer-to-a-pointer ability), when returning enumerators instead of result-types we can opt to use mutable objects as parameters.


public Exceptional Groovy(final MyResult in, MyResult out) {
out.wrapMe = "Some Response";
return Exceptional.ea_Good;
}


Indeed, going a step farther - when we choose to manage read-only - yet mutable parameters - with a simple final keyword, then when using mutable-parameter-results we can also choose to (1) pass-in a mutable object-result as a parameter, (2) be sure that the parameter-result-type has both an assignment and isNull() ability, and (3) now our code will be smaller, more efficient - as well as safer, too!


public void Cool() {
MyResult in = new MyResult();
MyResult out = new MyResult();
switch (Groovy(in, out)) {
case ea_Good:
break;
case ea_Bad:
break;
case ea_Ugly:
break;
default:
break;
}
}


Conclusion


After reading this article, I hope that you will consider using enumerators. IMO, the liberal use of even a single enumerator-set often combines together so as to make several versions of our products a lot more readable, maintainable, as well as easier to control.

Enjoy,

-Rn

(p.s. If you think that the idea of using enumeration in the place of tossing around exceptions is noteworthy, than you might also enjoy another post on using enumerators, too.)


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

<<First <Back | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | Next> Last>>