Survey
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the work of artificial intelligence, which forms the content of this project
Persistence
COMP434 Software
Design
Serialization - is the ability to save the state
of several objects to a stream
Persistence & using Beans from
applications
The stream is typically associated with a file,
but need not be (eg sending serialized objects
over a network connection)
Deserialization - is the ability to restore the
state of several objects from a stream
2
1
Persistence
Persistence
If an object contains references to other
objects, these are also saved
The process is automatic and recursive
Only nonstatic and nontransient parts of an
object’s state are saved by serialization
Static fields are considered part of the state of a class,
not the state of an object
A
1
2
C
B
4
3
D
5
8
6
7
E
9
Transient fields are not saved, since they contain
temporary data not needed to correctly restore the
object later
Some type info is also saved so the object can be
reconstructed properly
3
4
Persistence
Persistence
When an object is deserialized, none of its
constructors are invoked
Instead, memory is allocated and the
variables are set directly from the data that is
read from the serial stream
Some extra work needs to be done if
constructors perform actions that are
essential to getting an object running correctly
Static fields are sometimes initialized by static initialization
blocks that are executed when a class is loaded
The Serializable interface in the java.io
package defines no constants or methods
It exists simply to designate that an object
may be saved to and restored from a stream
An object can only be serialized if its class
implements this interface
Eg. Starting threads
5
A java.io.NotSerializableException is generated
if an attempt is made to serialize any object whose
class has not been defined in this manner
All Beans should implement this interface
6
1
Persistence
A Serializable Bean
Many of the classes provided with the JDK libraries
have been designed to be serializable
Eg. all of the Swing classes are Beans and are therefore
serializable
Objects of type Thread are not serializable
Implementation of threads is tightly coupled with the particular
platform on which the JVM (java virtual machine) is running
Almost none of the classes in java.io are serializable
Graph - shows six nodes positioned at the
corners of a hexagon
Uses a Node class for displaying nodes and a
Link class for drawing edges between nodes
Graph is serializable because all of its classes
either directly or indirectly implement
Serializable
However, there are many other types in the Java
class libraries that are not serializable
Ridiculous to consider “freezing” info about file handles, read/
write positions etc and expect to use it later - even on the same
machine
7
package graphs;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.JPanel;
public class Graph extends JPanel
implements MouseListener, MouseMotionListener {
private final static int NNODES = 6;
private Vector nodes;
private Vector links;
private transient Node node1, node2;
private transient int x, y;
public Graph() {
Dimension d = new Dimension(200, 200);
setMinimumSize(d); setPreferredSize(d); setMaximumSize(d);
nodes = new Vector();
links = new Vector();
addMouseListener(this);
addMouseMotionListener(this);
makeNodes();
} . . .
9
public void mouseReleased(MouseEvent me) {
// Make a link between node1 and node2
x = me.getX();
y = me.getY();
if(node1 != null) {
Enumeration e = nodes.elements();
while(e.hasMoreElements()) {
node2 = (Node)e.nextElement();
if(node2.contains(x, y)) {
makeLink(node1.getId(), node2.getId());
break;
}
}
node1 = node2 = null;
repaint();
}
}
11
. . .
8
public void mousePressed(MouseEvent me) {
// Check if node1 should be initialized
x = me.getX();
y = me.getY();
Enumeration e = nodes.elements();
while(e.hasMoreElements()) {
node1 = (Node)e.nextElement();
if(node1.contains(x, y)) {
return;
}
}
node1 = null;
}
. . .
10
public void mouseDragged(MouseEvent me) {
x = me.getX();
y = me.getY();
repaint();
}
. . .
12
2
package graphs;
import java.awt.*;
import java.io.*;
public void paintComponent(Graphics g) {
super.paintComponent(g);
// Draw nodes
for (int i = 0; i < nodes.size(); i++) {
((Node)nodes.elementAt(i)).draw(g);
}
// Draw links
for (int i = 0; i < links.size(); i++) {
((Link)links.elementAt(i)).draw(g);
}
// Draw rubber band line (if any)
if(node1 != null) {
g.drawLine(node1.getX(), node1.getY(), x, y);
}
}
public class Node implements Serializable {
private final static int NODERADIUS = 10;
private static int count = 0;
private int x, y, id;
public Node(int x, int y) {
this.x = x; this.y = y;
id = count++;
}
. . .
public boolean contains(int x, int y) {
int deltax = this.x – x;
int deltay = this.y – y;
int a = deltax * deltax + deltay * deltay;
int b = NODERADIUS * NODERADIUS;
return (a <= b);
}
. . .
} // end Node.java
. . .
// end Graph.java
13
14
Serialization Streams
Serialization Streams
Java provides stream classes to aid in the
serialization of Beans
ObjectOutputStream - in the java.io package
provides methods to serialize objects, arrays and
simple types to an output stream
Some methods:
void writeObject(Object o) - writes o to the stream
void defaultWriteObject() - writes the nonstatic and
nontransient fields of the current object to the stream (often
used during custom serialization)
void close() - closes the stream
Also assorted methods to write floats, chars, strings, arrays
etc. to the stream
ObjectStreamClass - in the java.io package
encapsulates information about a serialized
object
Instances of this class are created and stored in the
serial stream
This is the mechanism by which type information is
saved
Contains the name of the class and a long named
serialVersionUID
Unique identifier calculated from the class name and its
members (used for versioning)
15
16
Serialization Examples
Serialization Streams
ObjectInputStream - in the java.io package
provides methods to deserialize objects, arrays and
simple types from an input stream
Some methods:
Object readObject() - reads an object from the stream
void defaultReadObject() - reads the nonstatic and
nontransient fields of the current object from the stream (often
used during custom deserialization)
int available() - returns the number of bytes that are available for
reading
Also assorted methods to read floats, chars, strings, arrays etc.
from the stream
17
Saving and restoring objects
Two classes: one to save a Vector of objects to
a file and the other to read them in
18
3
package serial;
package serial;
import java.awt.*;
import java.io.*;
import java.util.*;
import java.io.*;
public class Save1 {
public static void main(String args[]) {
try {
Vector v = new Vector();
v.addElement(new Integer(-7));
v.addElement(new Rectangle(20, 20, 100, 50));
v.addElement("Hello");
System.out.println(v);
FileOutputStream fos = new FileOutputStream("save1.data");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(v);
oos.flush();
fos.close();
} catch(Exception ex) {
System.out.println("Exception: " + ex);
}
}
}
public class Restore {
public static void main(String args[]) {
try {
FileInputStream fis =
new FileInputStream(“save1.data”);
ObjectInputStream ois = new ObjectInputStream(fis);
Object obj = ois.readObject();
fis.close();
System.out.println(obj);
} catch(Exception ex) {
System.out.println("Exception: " + ex);
}
}
}
19
import java.awt.*;
import java.io.*;
Serialization Examples
20
Saving and restoring simple types and
your own objects
21
class Person implements Serializable {
private String name, phone;
public Person(String name, String phone) {
this.name = name;
this.phone = phone;
}
public String toString() {
return "[" + name + "," + phone + "]";
}
}
23
public class Save2 {
public static void main(String args[]) {
try {
FileOutputStream fos;
fos = new FileOutputStream("save2.data");
ObjectOutputStream oos;
oos = new ObjectOutputStream(fos);
oos.writeInt(5);
oos.writeDouble(Math.PI);
oos.writeBoolean(true);
oos.writeObject(Color.blue);
oos.writeChar('a');
oos.writeObject(new Person("Joe", "7834"));
oos.flush();
fos.close();
}
catch(Exception ex) {
System.out.println("Exception: " + ex);
}
}
}
22
package serial;
import java.io.*;
public class Restore2 {
public static void main(String args[]) {
try {
FileInputStream fis =
new FileInputStream("save2.data");
ObjectInputStream ois = new ObjectInputStream(fis);
System.out.println(ois.readInt());
System.out.println(ois.readDouble());
System.out.println(ois.readBoolean());
System.out.println(ois.readObject());
System.out.println(ois.readChar());
System.out.println(ois.readObject());
fis.close();
}
catch(Exception ex) {
System.out.println("Exception: " + ex);
}
}
24
}
4
Serialization Examples
Serialization Examples
Custom serialization
Sometimes the default serialization is not sufficient to save
and restore the state of an object
There are two methods provided by the Java designers for
this
Thread example:
Clock Bean that displays the current time in
hours, minutes and seconds
Internally uses a Thread to update the
display every second
Handle Threads, static variables etc.
private void writeObject(ObjectOutputStream oos) throws
IOException
private void readObject(ObjectInputStream ois) throws
IOException
Thread class is not serializable
These methods have two unusual characteristics:
They are not part of any interface to be implemented or class to be
extended
Even though the serialization support calls readObject and
writeObject they must be declared private methods
25
package clock;
import java.awt.*;
import java.io.*;
import java.text.*;
import java.util.*;
import javax.swing.JPanel;
import javax.swing.JLabel;
public class Clock extends JPanel implements Runnable {
private JLabel tf;
private transient Thread thread;
public Clock() {
tf = new JLabel("");
add(tf);
startThread();
}
. . .
27
26
private void startThread() {
thread = new Thread(this);
thread.start();
}
// implement the run method from Runnable
public void run() {
try {
SimpleDateFormat sdf;
sdf = new SimpleDateFormat("HH:mm:ss");
while(true) {
Thread.sleep(1000); // sleep for 1 second
tf.setText(sdf.format(new Date()));
}
} catch(Exception ex) { ex.printStackTrace(); }
}
private void readObject(ObjectInputStream ois)
throws IOException {
try {
ois.defaultReadObject();
startThread();
} catch(Exception ex) { ex.printStackTrace(); }
}
} // end Clock.java
Applications
Applications
Applications can dynamically create
instances of Beans
28
Some methods in java.beans.Beans
Object instantiate(ClassLoader clsLoader,
String beanName)
Component software philosophy - an
application need not provide every part of its
functionality, instead it can enlist the aid of
various components as needed
Uses clsLoader to instantiate the component named
beanName. If clsLoader is null, the System Class Loader is used
boolean isDesignTime()
Returns true if the execution environment is provided by a
builder tool
boolean isGuiAvailable()
The Beans class in java.beans has several
static methods to instantiate a Bean or
obtain information about its environment
Returns true if the execution environment supports an
interactive GUI
boolean isInstanceOf(Object bean, Class cls)
Returns true if bean is an instance of cls
29
30
5
package applications;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import spectrum2.*;
Examples
SpectrumApplication
Creates a JFrame, instantiates a Spectrum2
Bean, modifies its vertical property, adds the
Bean to the JFrame and makes the frame
visible
Requires that spectrum2 is in the
CLASSPATH
public class SpectrumApplication {
public static void main(String args[]) {
try {
final javax.swing.JFrame jf =
new javax.swing.JFrame("Spectrum application");
jf.setSize(200, 200);
jf.getContentPane().setLayout(null);
Spectrum2 spectrum =
(Spectrum2)Beans.instantiate(null, "spectrum2.Spectrum2");
spectrum.setVertical(false);
Dimension d = spectrum.getPreferredSize();
// reposition the Bean at 50, 50 and add to the frame
spectrum.setBounds(50, 50, d.width, d.height);
jf.getContentPane().add(spectrum);
. . .
31
jf.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
jf.dispose();
System.exit(0);
}
});
jf.setVisible(true);
} catch (Exception ex) {
ex.printStackTrace();
}
32
Examples
ColourSelectorApplication
Uses Selector and Painter Beans from the
cselector package (lecture 2)
}
} // end SpectrumApplication
Repackaged into cselector2 with a
BeanInfoClass for the Selector Bean that
specifies that Selector generates only one type of
event - a ColorEvent
Requires that cselector2 is in the
CLASSPATH
33
Examples
ColourSelectorApplication
1.
2.
3.
4.
5.
6.
Creates a JFrame, instantiates a Selector Bean and a
Painter Bean
Uses Introspection to obtain a BeanInfo object for the
Selector bean
Obtains the EventSetDescriptor for the first (and only)
event generated by Selector
Obtains the a Class object for the type of the listener
interface for this event and checks to see if Painter
implements this interface
Obtains a Method object representing the registration
method for the event type
Calls the invoke method in the registration method object
to register Painter to receive event notifications from
35
Selector
34
package applications;
import java.awt.*;
import java.awt.event.*;
import java.lang.reflect.*;
import java.beans.*;
import cselector2.*;
public class ColourSelectorApplication {
public static void main(String argv[]) {
try {
final javax.swing.JFrame jf =
new javax.swing.JFrame("Colour selector application");
jf.setSize(270, 250);
jf.getContentPane().setLayout(null);
Painter painter =
(Painter)Beans.instantiate(null, "cselector2.Painter");
Selector selector =
(Selector)Beans.instantiate(null, "cselector2.Selector");
Class selectorClass = selector.getClass();
BeanInfo bi1 = null;
try {
bi1 = Introspector.getBeanInfo(selectorClass);
} catch(Exception ex) {
ex.printStackTrace(); System.exit(1);
36
}
6
// Get the EventSetDescriptor objects selector
EventSetDescriptor [] esds = bi1.getEventSetDescriptors();
// Get the listener class for the first event type
Class listenerType = esds[0].getListenerType();
// Check to see if Painter implements this listener
if (Beans.isInstanceOf(painter, listenerType)) {
// now try to register Painter with Selector to receive
// this type of event.
// First obtain the registration method
Method registerMethod = esds[0].getAddListenerMethod();
// Invoke the registration method of Selector to
// register Painter
Object args[] = new Object[1];
args[0] = painter;
try {
registerMethod.invoke(selector, args);
} catch(Exception ex) {
ex.printStackTrace();
System.exit(1);
}
}
Examples
ColourSelectorApplication2
Similar to the first example but uses a
dynamic EventHandler to link the Painter to
the Selector
Uses introspection to find out about events,
properties and methods
37
. . . // the rest is similar to SpectrumApplication (see source)
38
// Get the EventSetDescriptors for the source bean
EventSetDescriptor [] esds = bi1.getEventSetDescriptors();
// Get the named source and target & instantiate them
String source = argv[0]; String target = argv[1];
Object sourceO = Beans.instantiate(null, source);
Object targetO = Beans.instantiate(null, target);
// Store class objects for the source and target
Class sourceClass = sourceO.getClass();
Class targetClass = targetO.getClass();
System.out.println("Events:");
for (int i = 0; i < esds.length; i++) {
System.out.println("("+i+") "+esds[i].getName());
}
System.out.print("Choose event: ");
char c;
String result = "";
while ((c = (char)System.in.read()) != '\n') {
result += c;
}
// Get the listener class for the chosen event type
Class listenerType =
esds[Integer.parseInt(result)].getListenerType();
// Store the registration method for this listener type
Method registerMethod =
esds[Integer.parseInt(result)].getAddListenerMethod();
BeanInfo bi1 = null;
BeanInfo bi2 = null;
try {
bi1 = Introspector.getBeanInfo(sourceClass);
bi2 = Introspector.getBeanInfo(targetClass);
}…
. . .
. . .
39
// Get the method descriptors from the target
MethodDescriptor [] md = bi2.getMethodDescriptors();
System.out.println("\nTarget methods: ");
for (int i = 0; i < md.length; i++) {
Class [] paramTypes = md[i].getMethod().getParameterTypes();
// Print out only target methods that take a single argument
if (paramTypes.length == 1) {
System.out.print("("+i+") "+md[i].getName()+"( ");
for (int j = 0; j < paramTypes.length; j++) {
System.out.print(paramTypes[j].getName()+" ");
}
System.out.println(")");
}
}
System.out.print("Choose target method: ");
result = "";
while ((c = (char)System.in.read()) != '\n') {
result += c;
}
// Store the parameter type of the chosen method and the method
Class targetArg =
md[Integer.parseInt(result)].getMethod().
getParameterTypes()[0];
41
Method targetMethod = md[Integer.parseInt(result)].getMethod();
40
// Look for source properties that are the same type as
// the targetArg
PropertyDescriptor [] pds = bi1.getPropertyDescriptors();
System.out.println("\nMatching source getter methods: ");
for (int i = 0; i < pds.length; i++) {
// Get the read method of this property
Method rm = pds[i].getReadMethod();
if (rm != null) {
// Find out the return type
Class sourceRRT = rm.getReturnType();
if (sourceRRT.getName().equals(targetArg.getName())) {
System.out.println("("+i+") "+rm.getName());
}
}
}
System.out.print("Choose getter method: ");
result = "";
while ((c = (char)System.in.read()) != '\n') {
result += c;
}
// Store the read method for the source property
Method sourceProperty =
pds[Integer.parseInt(result)].getReadMethod();
42
7
// Make a dynamic handler that implements the listener
// interface for the chosen event type
Object handler =
EventHandler.create(listenerType, targetO,
targetMethod.getName(),
"source."+sourceProperty.getName());
// Invoke the registration method of source to
// register the handler
Object args[] = new Object[1];
args[0] = handler;
try {
registerMethod.invoke(sourceO, args);
} catch(Exception ex) {
ex.printStackTrace(); System.exit(1);
}
43
8