Created
September 17, 2018 19:24
-
-
Save rupert-ong/b4dbae87302e13be20e8d406480b85aa to your computer and use it in GitHub Desktop.
Java Serialization, Deserialization and Transient Fields #java #serialization #deserialization #transient #objectoutputstream #objectinputstream
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.Serializable; | |
import java.util.HashMap; | |
import java.util.Map; | |
/** | |
* Used to illustrate transient (don't get serialized) fields. | |
* Useful for values that are derived from other members, like totals. | |
* For deserialization, you must specify the value for transient fields in the readObject method | |
*/ | |
public class AccountGroup implements Serializable { | |
private static final long serialVersionUID = -7665535201427596893L; | |
private Map<String, BankAccount> accountMap = new HashMap<>(); | |
private transient int totalBalance; | |
public int getTotalBalance() { return totalBalance; } | |
public void addAccount(BankAccount acct) { | |
totalBalance += acct.getBalance(); | |
accountMap.put(acct.getId(), acct); | |
} | |
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { | |
// Return default values for other fields | |
in.defaultReadObject(); | |
// Set value for totalBalance by deriving it from hash map | |
for(BankAccount acct : accountMap.values()) | |
totalBalance += acct.getBalance(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import java.io.Serializable; | |
public class BankAccount implements Serializable { | |
// Type serialver -show in cmd prompt of output directory to get serialUID | |
// serialVersionUID used to identify and maintain (backwards) compatibility | |
// when updating this file when deserializing | |
private static final long serialVersionUID = 690408737872309788L; | |
private String id; | |
private int balance; | |
private char lastTxType; | |
private int lastTxAmount; | |
public BankAccount(String id) { | |
this.id = id; | |
} | |
public BankAccount(String id, int balance) { | |
this.id = id; | |
this.balance = balance; | |
} | |
public String getId(){ | |
return this.id; | |
} | |
public synchronized int getBalance(){ | |
return this.balance; | |
} | |
public synchronized void deposit(int amt) { | |
this.balance += amt; | |
this.lastTxAmount = 'd'; | |
this.lastTxAmount = amt; | |
} | |
public synchronized void withdraw(int amt) { | |
this.balance -= amt; | |
this.lastTxAmount = 'w'; | |
this.lastTxAmount = amt; | |
} | |
// Use custom serialization and deserialization to determine what we | |
// want to write and have returned in instances where BankAccount changes | |
// and we do not want to return default member values, which may be misleading. | |
// In the case of lastTxAmount and lastTxType, default returns of 0 and null | |
// are misleading, as it implies no recent transactions took place (if we changed | |
// BankAccount to include those members after having serialized an earlier, simpler version | |
// with only id and balance in it) | |
/** | |
* Use by serialize process, specify to use the default serialization (example) | |
* @param out ObjectOutputStream | |
* @throws IOException | |
*/ | |
private void writeObject(ObjectOutputStream out) throws IOException { | |
out.defaultWriteObject(); | |
} | |
/** | |
* Used by deserialize process to extract fields for our class type | |
* @param in ObjectInputStream | |
* @throws IOException | |
* @throws ClassNotFoundException | |
*/ | |
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { | |
ObjectInputStream.GetField fields = in.readFields(); | |
// Determine the default values to return in the case no value is found... | |
id = (String) fields.get("id", null); | |
balance = fields.get("balance", 0); | |
lastTxType = fields.get("lastTxType", 'u'); | |
lastTxAmount = fields.get("lastTxAmount", -1); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import java.nio.file.Files; | |
import java.nio.file.Paths; | |
public class Main { | |
public static void main(String[] args) { | |
// serializeBankAccount(); | |
// deserialzeBankAccount(); | |
// serializeTransientExample(); | |
deserializeTransientExample(); | |
} | |
private static void serializeTransientExample() { | |
BankAccount acct1 = new BankAccount("1234", 500); | |
BankAccount acct2 = new BankAccount("9876", 750); | |
AccountGroup group = new AccountGroup(); | |
group.addAccount(acct1); | |
group.addAccount(acct2); | |
saveGroup(group, "group.dat"); | |
} | |
private static void deserializeTransientExample() { | |
AccountGroup group = loadGroup("group.dat"); | |
System.out.println("Total balance: " + group.getTotalBalance()); | |
} | |
private static void deserialzeBankAccount() { | |
BankAccount ba = loadAccount("account.dat"); | |
System.out.println("Deserialized BankAccount: " + ba.getBalance()); | |
} | |
private static void serializeBankAccount() { | |
BankAccount acct = new BankAccount("1234", 500); | |
acct.deposit(50); | |
saveAccount(acct, "account.dat"); | |
} | |
/** | |
* Serialize BankAccount by writing it into a file using ObjectOutputStream | |
* | |
* @param ba BankAccount type instance | |
* @param filename Filename to write serialized object into | |
*/ | |
private static void saveAccount(BankAccount ba, String filename) { | |
try (ObjectOutputStream objectStream = new ObjectOutputStream(Files.newOutputStream(Paths.get(filename)))) { | |
objectStream.writeObject(ba); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Deserialize BankAccount by reading it from a file using ObjectInputStream | |
* | |
* @param filename Filename to deserialize object from | |
* @return BankAccount type instance | |
*/ | |
private static BankAccount loadAccount(String filename) { | |
BankAccount ba = null; | |
try (ObjectInputStream objectStream = new ObjectInputStream(Files.newInputStream(Paths.get(filename)))) { | |
ba = (BankAccount) objectStream.readObject(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} | |
return ba; | |
} | |
/** | |
* Serialize AccountGroup | |
* | |
* @param group AccountGroup | |
* @param filename Filename to serialize object into | |
*/ | |
private static void saveGroup(AccountGroup group, String filename) { | |
try (ObjectOutputStream objectStream = | |
new ObjectOutputStream(Files.newOutputStream(Paths.get(filename)))) { | |
objectStream.writeObject(group); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} | |
} | |
/** | |
* Deserialize Account Group | |
* | |
* @param filename Filename to deserialize object from | |
* @return AccountGroup | |
*/ | |
private static AccountGroup loadGroup(String filename) { | |
AccountGroup g = null; | |
try (ObjectInputStream objectStream = | |
new ObjectInputStream(Files.newInputStream(Paths.get(filename)))) { | |
g = (AccountGroup) objectStream.readObject(); | |
} catch (IOException e) { | |
e.printStackTrace(); | |
} catch (ClassNotFoundException e) { | |
e.printStackTrace(); | |
} | |
return g; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment