Problem
Your code currently writes the JSON or XML streams out to text files. When the data is read back in it is very difficult to reconstruct java objects from those text streams. In this next activity you are going to write and read the java objects directly to and from a file using java serialization. You are going to update your code so that the java objects can be serialized to a file.
Once all your classes are Serializable, some thought needs to be given to how you implement the relationship between the objects, are they one way or two way, and what type of collections should be used.
Solution
Each file that needs to be Serialized must be marked as Serializable by implementing the Serializable interface, mark the Product class as Serializable
public class Product implements Serializable
{
Now implement the SerializableFileWriter
public class SerializableFileWriter implements OutputChannel
{
private String itsFileName;
private ObjectOutputStream itsOutputStream;
public SerializableFileWriter()
{
}
@Override
public void openForWriting( String fname )
{
itsFileName = fname;
try
{
itsOutputStream = new ObjectOutputStream(new FileOutputStream(fname));
} catch (IOException ex)
{
Logger.getLogger(TextFileWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void write( Product theObject )
{
try
{
itsOutputStream.writeObject(theObject);
} catch (IOException ex)
{
Logger.getLogger(SerializableFileWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public void close()
{
try
{
itsOutputStream.close();
} catch (IOException ex)
{
Logger.getLogger(SerializableFileWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
The write(...) method as we have declared it is restictive. The API guide indicates that the signature for OutputStream.writeObject(Object stream) is an Object, so we can change the signature of the write(...) method to
@Override
public void write( Object theObject )
{
try
{
itsOutputStream.writeObject(theObject);
} catch (IOException ex)
{
Logger.getLogger(SerializableFileWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
Modify the Writer class so it has new factory method
public static SerializableFileWriter getSerializableFileWriter( String fname )
{
serializableWriter.openForWriting(fname);
return serializableWriter;
}
Implement a new class called SerializableFileReader with the following signatures. Use this class to load the object from the filesystem into your code
public class SerializableFileReader
{
private String itsFileName;
private ObjectInputStream itsInputStream;
public SerializableFileReader()
{
}
@Override
public void openForReading( String fname )
{
itsFileName = fname;
try
{
itsInputStream = new ObjectInputStream(new FileInputStream(fname));
} catch (IOException ex)
{
Logger.getLogger(TextFileWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
@Override
public Object read()
{
Object result = null;
try
{
result = itsInputStream.readObject();
}catch (IOException | ClassNotFoundException ex)
{
Logger.getLogger(TextFileReader.class.getName()).log(Level.SEVERE, null, ex);
}
finally
{
close();
}
return result;
}
@Override
public void close()
{
try
{
itsInputStream.close();
} catch (IOException ex)
{
Logger.getLogger(TextFileReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Refactoring
Updated version of InputChannel
public interface InputChannel
{
public void openForReading( String fname );
public Object read();
public void close();
}
Modified version of SerializableFileReader
public class SerializableFileReader implements InputChannel
{
Implement the Reader class
public class Reader
{
private static final TextFileReader textFileReader = new TextFileReader();
private static final SerializableFileReader serializableReader = new SerializableFileReader();
public static InputChannel getTextFileReader( String fname )
{
textFileReader.openForReading(fname);
return textFileReader;
}
public static InputChannel getSerializableFileReader( String fname )
{
serializableReader.openForReading(fname);
return serializableReader;
}
}
In order to test our code, add the following lines of code the main() method
public static void main(String[] args)
{
MainUnit munit = new MainUnit();
munit.bootstrap_products_items();
munit.test_serialization_writer_all_products();
munit.test_serialization_reader_all_products();
munit.bootstrap_customers_accounts();
munit.test_serialization_writer_all_customers();
munit.test_serialization_reader_all_customers();
System.out.println("=============================================================================");
System.out.println("=============================================================================\n");
munit.bootstrap_orders_accounts_items();
munit.test_serialization_writer_all_objects();
munit.test_serialization_reader_all_objects();
}
Now implement each method
public void bootstrap_products_items()
{
// This call will bootstrap the products
Warehouse.getInstance();
}
public void test_serialization_writer_all_products()
{
String fname = "c:\\tmp\\all-products.oos";
// working with a Serializable File Writer
SerializableFileWriter sfw = Writer.getSerializableFileWriter(fname);
// Write the object out
// HashMap are Serializable, so it can be written straight out
// Because all objects in the HashMap are Serializable, they will all be
// written out as well
sfw.write( Warehouse.getInstance().getProducts());
sfw.close();
}
public void test_serialization_reader_all_products()
{
String fname = "c:\\tmp\\all-products.oos";
// Read the object from the filesystem
InputChannel sfr = Reader.getSerializableFileReader(fname);
sfr.openForReading(fname);
// Read the entire object network back in
HashMap< String, Product> productsIn = (HashMap< String, Product>) sfr.read();
// Only process the objects if the read was successful
if (productsIn != null)
{
// Iterate over all the Products...
for (Map.Entry<String, Product> entry : productsIn.entrySet())
{
Product pp = entry.getValue();
System.out.printf("Product ==> %s, %f, %s, %d\n", pp.getDescription(), pp.getPrice(), pp.getProductCode(), pp.getQuantity());
// Iterate over all the Items within each Product
for (Map.Entry<Integer, Item> itemEntry : pp.getItems().entrySet())
{
Item anItem = itemEntry.getValue();
System.out.printf("Item ==> %f, %d\n", anItem.getItemCost(), anItem.getUniqueId());
}
}
}
}
public void bootstrap_customers_accounts()
{
CustomerAccountMgr caMgr = CustomerAccountMgr.getInstance();
// Create the accounts first and Customers
Account acc = null;
Customer cc = null;
cc = new Customer("Sevlyn", "Wright", LocalDate.of(1965, 5, 8), "Somewhere in Birmingham");
caMgr.addCustomer("C1", cc);
acc = new Account(cc, 1);
cc.setAccount(acc); // tie acc to the customer
caMgr.addAccount(acc);
cc = new Customer("Samuel", "Wright", LocalDate.of(1982, 4, 22), "Somewhere else in Birmingham");
caMgr.addCustomer("C2", cc);
acc = new Account(cc, 2);
cc.setAccount(acc); // tie acc to the customer
caMgr.addAccount(acc);
cc = new Customer("Graham", "Meaden", LocalDate.of(1967, 4, 3), "Somewhere down South");
caMgr.addCustomer("C3", cc);
acc = new Account(cc, 3);
cc.setAccount(acc); // tie acc to the customer
caMgr.addAccount(acc);
}
public void test_serialization_writer_all_customers()
{
String fname = "c:\\tmp\\all-customers.oos";
// working with a Serializable File Writer
SerializableFileWriter sfw = Writer.getSerializableFileWriter(fname);
// Write the object out
// HashMap are Serializable, so it can be written straight out
// Because all objects in the HashMap are Serializable, they will all be
// written out as well
sfw.write(CustomerAccountMgr.getInstance().getCustomers());
// No need to write the accounts because they are linked to the customers
sfw.close();
}
public void test_serialization_reader_all_customers()
{
String fname = "c:\\tmp\\all-customers.oos";
// Read the object from the filesystem
InputChannel sfr = Reader.getSerializableFileReader(fname);
sfr.openForReading(fname);
// Read the entire object network back in
HashMap< String, Customer> customersIn = (HashMap< String, Customer>) sfr.read();
// Only process the objects if the read was successful
if (customersIn != null)
{
// Iterate over all the Customers...
for (Map.Entry<String, Customer> entry : customersIn.entrySet())
{
Customer cc = entry.getValue();
System.out.printf("Customer ==> %s, %s, %s, %s, %s\n",
entry.getKey(),
cc.getFname(),
cc.getLname(),
cc.getDob().toString(),
cc.getAddress());
System.out.printf("\tAccount ==> %d, %s\n",
cc.getAccount().getAccountId(),
cc.getAccount().getDateCreated().toString());
}
}
}
If the serialization is successful, you are now ready to implement bootstrap_orders_accounts_items(), this is our implementation
/*
* This method will use an Order object to link the Item and Product objects
* to the Customer and Account objects
*/
public void bootstrap_orders_accounts_items()
{
// Get an account and a product
Account acc = CustomerAccountMgr.getInstance().getAccount(1);
Product pp = Warehouse.getInstance().getProduct("JDF-001");
// only proceed if the keys were valid
if (acc != null && pp != null)
{
try
{
// create new order giving it the order number of 1
Order oo = new Order(acc, 1, LocalDate.now());
// add the order the account
acc.addOrder(oo);
// get an item from the product, remember Items represent real things
// Products are descriptions of thise things
Item itm = pp.getItem(1);
// Set the quantity attribute, how many instances of the Item
itm.setQuantity(3);
// Only proceed if you used a valid item id
if (itm != null)
{
oo.addItem(itm); // this call decrease the stock for this product
}
} catch (Exception ex)
{
Logger.getLogger(MainUnit.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void test_serialization_writer_all_objects()
{
String fname = "c:\\tmp\\all-objects.oos";
// working with a Serializable File Writer
SerializableFileWriter sfw = Writer.getSerializableFileWriter(fname);
// Write the object out
// HashMap are Serializable, so it can be written straight out
// Because all objects in the HashMap are Serializable, they will all be
// written out as well
sfw.write(CustomerAccountMgr.getInstance().getCustomers());
sfw.close();
}
public void test_serialization_reader_all_objects()
{
String fname = "c:\\tmp\\all-objects.oos";
// Read the object from the filesystem
InputChannel sfr = Reader.getSerializableFileReader(fname);
sfr.openForReading(fname);
// Read the entire object network back in
HashMap< String, Customer> customersIn = (HashMap< String, Customer>) sfr.read();
// Only process the objects if the read was successful
if (customersIn != null)
{
// Iterate over all the Customers...
for (Map.Entry<String, Customer> entry : customersIn.entrySet())
{
Customer cc = entry.getValue();
System.out.printf("Customer ==> %s, %s, %s, %s, %s\n",
entry.getKey(),
cc.getFname(),
cc.getLname(),
cc.getDob().toString(),
cc.getAddress());
System.out.printf("\tAccount ==> %d, %s\n",
cc.getAccount().getAccountId(),
cc.getAccount().getDateCreated().toString());
displayAccountOrderDetais(cc.getAccount());
}
}
}
public void displayAccountOrderDetais(Account acc)
{
HashMap< Integer, Order> orders = acc.getOrders();
for (Map.Entry<Integer, Order> entry : orders.entrySet())
{
Order ord = entry.getValue();
System.out.printf("Order ==> %d, %f, %s\n",
ord.getOrderNo(),
ord.getTotalCost(),
ord.getDateCreated().toString());
displayOrderDetails(ord);
}
}
public void displayOrderDetails(Order ord)
{
for (Item itm : ord.getItems())
{
System.out.printf("Item ==> %d, %f, %d\n",
itm.getUniqueId(),
itm.getItemCost(),
itm.getQuantity());
System.out.printf("Product ==> %s has %d in stock\n",
itm.getProduct().getDescription(),
itm.getProduct().getQuantity());
}
}
}
Related articles
-
Page:
-
Page:
-
Page:
-
Page:
-
Page: