Example: Canonical Form for Reference Objects using Eclipse

A reference object has one or more modifiable fields. (More on this later.)

A document has a title and content. Both can be modified. The title can change, words can be added to and removed from the content.

Here's a class diagram for Document:

In Eclipse we can add a new class to a project using the New java Class dialog:

Note that we added Serializable to the implemented interfaces. Serializable objects can be saved to files and read from files:

ObjectOutputStream os = null;
Document doc = new Document();
try {
   os = new ObjectOutputStream(new FileOutputStream("essay"));
   os.writeObject(doc);
   }
} catch(Exception e) {

}

ObjectInputStream is = null;
try {
   is = new ObjectInputStream(new FileInputStream("essay"));
   doc = (Envelope)is.readObject();
} catch(Exception e) {

}

Eclipse offers to add a version field. This number will be saved to output files during serialization. If it differs from the version number when the file is read later, then the JVM will know that the document is obsolete.

We add two more fields corresponding to title and content:

import java.io.Serializable;
import java.util.Collection;


/**
 * @author pearce
 *
 */
public class Document implements Serializable {

   private static final long serialVersionUID = 1L;
   private String title;
   private Collection<String> content;

}

Note that the content field is a collection from Java's Collections Framework. Collections are easier to manage than arrays.

Next, we generate the principle constructor using Eclipse's "Generate Constructor" dialog:

We also add a derived constructor:

import java.io.Serializable;
import java.util.Collection;
import java.util.LinkedList;


/**
 * @author pearce
 *
 */
public class Document implements Serializable {

   private static final long serialVersionUID = 1L;
   private String title;
   private Collection<String> content;
   /**
    * Initializes this document
    * @param title the title of this document
    */
   public Document(String title) {
      super();
      this.title = title;
     
      content = new LinkedList<String>();
   }
  
   /**
    * Initializes this document with default title
    */
   public Document() {
      this("My Document");
   }
  
}

It's a good idea to have a parameterless constructor. Many places in Java assume that such a constructor exists.

For example, the following code won't compile unless Document has a parameterless constructor:

class Letter extends Document {
   public Letter() {
      super();
   }
   // etc.
}

Fields that aren't collections should have getter and setter methods. We can use Eclipse's Generate Getters and Setters dialog to create them:

Here's the code so far:

public class Document implements Serializable {

   private static final long serialVersionUID = 1L;
   private String title;
   private Collection<String> content;
   /**
    * Initializes this document
    * @param title the title of this document
    */
   public Document(String title) {
      super();
      this.title = title;
     
      content = new LinkedList<String>();
   }
  
   /**
    * Initializes this document with default title
    */
   public Document() {
      this("My Document");
   }

   /**
    * @return the title
    */
   public String getTitle() {
      return title;
   }

   /**
    * @param title the title to set
    */
   public void setTitle(String title) {
      this.title = title;
   }
  
}

For collection fields, we generate methods that delegate to the collection's methods. We can use Eclipse's Generate Delegate Methods dialog for this:

Here's the code:

public class Document implements Serializable {

   private static final long serialVersionUID = 1L;
   private String title;
   private Collection<String> content;
   /**
    * Initializes this document
    * @param title the title of this document
    */
   public Document(String title) {
      super();
      this.title = title;
     
      content = new LinkedList<String>();
   }
  
   /**
    * Initializes this document with default title
    */
   public Document() {
      this("My Document");
   }

   /**
    * @return the title
    */
   public String getTitle() {
      return title;
   }

   /**
    * @param title the title to set
    */
   public void setTitle(String title) {
      this.title = title;
   }

   /**
    * @param e
    * @return
    * @see java.util.Collection#add(java.lang.Object)
    */
   public boolean add(String e) {
      return content.add(e);
   }

   /**
    * @return
    * @see java.util.Collection#iterator()
    */
   public Iterator<String> iterator() {
      return content.iterator();
   }

   /**
    * @param o
    * @return
    * @see java.util.Collection#remove(java.lang.Object)
    */
   public boolean remove(Object o) {
      return content.remove(o);
   }

   /**
    * @return
    * @see java.util.Collection#size()
    */
   public int size() {
      return content.size();
   }
  
}

Here's an example of how we could print each word in the content of a document on a single line:

Iterator<String> p = doc.iterator();
while (p.hasNext()) {
   System.out.println(p.next());
}