Hey everyone,

I've never used eclipse or java, and I have an assignment that is expected to use the XML encoding/decoding functionality. I've searched google a bit, but can't really find a good example. Does anyone have a link to some snippets or something that I could go by?

So I've made it somewhere with this ... but I'm stuck again. Here's what I have so far:

package main;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class Main {

	public static void main(String[] args) throws FileNotFoundException {

		Shelf TestShelf = new Shelf("My Shelf");
		Shelf TestShelf2 = new Shelf();

		TestShelf.PrintProperties();

		XMLEncoder e = new XMLEncoder(new BufferedOutputStream(
				new FileOutputStream("Test.xml")));
		e.writeObject(TestShelf);
		e.writeObject(TestShelf2);
		e.close();
	
		XMLDecoder d = new XMLDecoder(new BufferedInputStream(
				new FileInputStream("Test.xml")));
		Object result = d.readObject();
		System.out.println("Object: " + result);
		result = d.readObject();
		System.out.println("Object: " + result);
	}
}

Which gives me this xml:

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0" class="java.beans.XMLDecoder">
 <object class="main.Shelf">
  <void property="shelfID">
   <int>0</int>
  </void>
  <void property="shelfName">
   <string>My Shelf</string>
  </void>
 </object>
 <object class="main.Shelf">
  <void property="shelfID">
   <int>1</int>
  </void>
  <void property="shelfName">
   <string>New Shelf1</string>
  </void>
 </object>
</java>

And this output:


Shelf Name: My Shelf
Shelf ID: 0
Object: main.Shelf@169dd64
Object: main.Shelf@145f5e3

My question is, how can I extract exact values from my XML document? For example if I wanted to 'recreate' my saved XML session every time I load my program ... how can I access individual properties?

Object cast is required.

Shelf result =(Shelf) d.readObject();
System.out.println("Object: " + result.getShelfID() + " " + result.getShelfName());

>how can I extract exact values from my XML document?

Correct me if I'm wrong. I think there is no direct way to do so. What I'm telling you to read objects (Deserialize) from the XML document and push them into the ArrayList<Self> collection. What do you think about to serialize List<T>?

Oh ok, that makes a lot of sense. So when I write my save() method, I write my list of shelves to an xml file ... when I write my restore() method, I guess I could do like:

getNumberOfShelves()
for ( .... .... ....)
readXML() and setProperties()

Seems a little complex though - is there an easier way I'm not aware of?

ArrayLists are serialisable, so if you put all your Shelves into an ArrayList<Shelf> object you can write that to XML as a single object, and read it back with a single read. How simple is that?

Oh very cool. So even though my Shelf will have Notebooks -> Notes, I can restore everything as long as I store the Shelves in a single ArrayList?

Yes, if all the individual classes can be serialised, then so can collections of them. Similarly if a class contains instances of another (serialisable) class it will serialise completely. I'm assuming Shelf, Notebook, Note are all serialisable?

I'm not sure ... I'm pretty new to this. Do I just need to keep doing this:

public class Shelf implements java.io.Serializable

I honestly have no idea what java.io.Serializable does.

Edited 5 Years Ago by Duki: n/a

Its a "marker" interface - ithas no methods or anything, it just tells the compiler that the class is OK to serialise. I think its not actually needed for XML serialisation.As long as your classes all come down to simple things like ints and Strings in the end you'll be OK.

So I'm at a bit of a road block. I'm trying to save my Session which consists of an ArrayList Shelf, which in turn contains an ArrayList Notebook.

I can save the Session, but the only thing written to the xml is the Shelf, not the Notebook contained within the shelf.

Here's my updated code:

package main;

import java.util.ArrayList;

public class Shelf implements java.io.Serializable {

	public Shelf() {
		shelfName = "New Shelf" + nextShelfID;
		shelfID = nextShelfID;
		nextShelfID++;
	};

	public Shelf(String name) {
		shelfName = name;
		shelfID = nextShelfID;
		nextShelfID++;
	};

	private String shelfName;
	static private int nextShelfID = 0;
	private int shelfID;

	public ArrayList<Notebook> notebooks = new ArrayList<Notebook>();

	public void setShelfName(String name) {
		shelfName = name;
	}

	public String getShelfName() {
		return shelfName;
	}

	public int getShelfID() {
		return shelfID;
	}

	public void setShelfID(int id) {
		shelfID = id;
	}

	public int getNextShelfID() {
		return nextShelfID;
	}

	public void PrintProperties() {
		System.out.println("Shelf Name: " + shelfName);
		System.out.println("Shelf ID: " + shelfID);
	}
}
package main;
import java.util.ArrayList;

public class Notebook implements java.io.Serializable{
	
	public Notebook() {
		notebookName = "New Notebook" + nextNotebookID;
		notebookID = nextNotebookID;
		nextNotebookID++;
	};

	public Notebook(String name) {
		notebookName = name;
		notebookID = nextNotebookID;
		nextNotebookID++;
	};

	private String notebookName;
	static private int nextNotebookID = 0;
	private int notebookID;

	private ArrayList<Note> notes = new ArrayList<Note>();

	public void setNotebookName(String name) {
		notebookName = name;
	}

	public String getNotebookName() {
		return notebookName;
	}

	public int getNotebookID() {
		return notebookID;
	}

	public void setNotebookID(int id) {
		notebookID = id;
	}

	public int getNextNotebookID() {
		return nextNotebookID;
	}

	public void PrintProperties() {
		System.out.println("Notebook Name: " + notebookName);
		System.out.println("Notebook ID: " + notebookID);
	}

}
public static void SaveActiveSession(ArrayList SessionToBeSaved)
			throws FileNotFoundException {
		XMLEncoder e = new XMLEncoder(new BufferedOutputStream(
				new FileOutputStream("Test.xml")));
		e.writeObject(SessionToBeSaved);
		e.close();
	}
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0" class="java.beans.XMLDecoder">
 <object class="java.util.ArrayList">
  <void method="add">
   <object class="main.Shelf" id="Shelf0">
    <void property="shelfID">
     <int>0</int>
    </void>
    <void property="shelfName">
     <string>New Shelf0</string>
    </void>
   </object>
  </void>
 </object>
</java>

Edited 5 Years Ago by Duki: n/a

My gets/sets are the same for both classes though, aren't they?

notebooks in the Shelf class doesn't have public get/set methods, so it doesn't get processed. You need something like

public ArrayList<Note> getNotebooks() {
      return notebooks;
   }

   public void setNotebooks(ArrayList<Note> notebooks) {
      this.notebooks= notebooks;
   }

(and the same for notes in Notebook)

Edited 5 Years Ago by JamesCherrill: n/a

Hm, still not writing out anything. Here's my Shelf class again, with the methods you suggested:

package main;

import java.util.ArrayList;

public class Shelf implements java.io.Serializable {

	public Shelf() {
		shelfName = "New Shelf" + nextShelfID;
		shelfID = nextShelfID;
		nextShelfID++;
	};

	public Shelf(String name) {
		shelfName = name;
		shelfID = nextShelfID;
		nextShelfID++;
	};

	private String shelfName;
	static private int nextShelfID = 0;
	private int shelfID;

	public ArrayList<Notebook> notebooks = new ArrayList<Notebook>();

	public void setShelfName(String name) {
		shelfName = name;
	}
	
	public ArrayList<Notebook> getNotebooks() {
	      return this.notebooks;
	   }

	   public void setNotebooks(ArrayList<Notebook> notebooks) {
	      this.notebooks = notebooks;
	   }

	public String getShelfName() {
		return shelfName;
	}

	public int getShelfID() {
		return shelfID;
	}

	public void setShelfID(int id) {
		shelfID = id;
	}

	public int getNextShelfID() {
		return nextShelfID;
	}

	public void PrintProperties() {
		System.out.println("Shelf Name: " + shelfName);
		System.out.println("Shelf ID: " + shelfID);
	}
}

Edited 5 Years Ago by Duki: n/a

Don't mix the definition of bean and list classes. Try to define a new list class.

For instance,

Foo.java

package main;

public class Foo
{
   private int id;
   private String name="";

   public Foo() {}
   public Foo(int id,String name) { this.id=id; this.name=name;}
   public int getId() { return id;}
   public String getName() { return name;}
   public void setId(int id) { this.id=id;}
   public void setName(String name) { this.name=name;}
}

FooList.java

package main;

import java.util.ArrayList;

public class FooList extends ArrayList<Foo>
{
  public void add(int id,String name) {
       super.add(new Foo(id,name));
  } 
  public void show(){
     for(Foo f:this) 
        System.out.println(f.getId() +  " " + f.getName());
  }
  public Foo getById(int id){
     for(Foo f:this) 
      {
        if(f.getId()==id)
          return f;
      }
     return null;
  }
}

FooMain.java

package main;

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class FooMain
{
  public static void main(String []args) 
  {
    
     FooList list=new FooList();
     list.add(1,"A");
     list.add(2,"B");

    try{
     XMLEncoder encode=new XMLEncoder(new BufferedOutputStream(
			 new FileOutputStream("Test.xml")));
     encode.writeObject(list);
     encode.close();
     }catch(Exception ex){
       ex.printStackTrace();
     }


     try{

     XMLDecoder decode = new XMLDecoder(new BufferedInputStream(
				new FileInputStream("Test.xml")));
     FooList result = (FooList)decode.readObject();
     decode.close();

     result.show(); // print all objects

     Foo f=result.getById(2); //Search by id
     if(f!=null)
       System.out.println(f.getId() + " "+ f.getName());
     	 

     }catch(Exception ex) {
       ex.printStackTrace();
     }
  }
}

>Don't mix the definition of bean and list classes. Try to define a new list class.

That's not really an option at this point - is there any other way around this?

You don't have to create e new list class to use XML encoder, although there may be other design reasons why it would be a good idea.
Is this working yet? If not, perhaps you can post the complete current code, because there's no obvious reason why it won't work.

The code is quite big at this point - however, I will post if absolutely necessary. As a general idea of what I'm trying to do, I have the following setup:

Notebook (class)
  --- contains Array of Notes (class)
  --- contains Array of Tags (class)


Note (class)
  --- contains Array of Tags (class)
  --- contains members (e.g., String for the note text)

Tag (class)
  --- contains members (e.g., String for tag text)

So, I'd like to be able to save the Notebook to XML and also restore these objects if requested. As for naming and methods, is there anything other than getMember, setMember methods I need?

Edited 5 Years Ago by Duki: n/a

So if everything is stored in a single Notebook object, and I write that object to XML ... it will recursively go through and write all it's objects, and it's object's-objects, it's arrays, it's member object's arrays etc.?

Edited 5 Years Ago by Duki: n/a

Ok, here's my updated code ... I can't get the ArrayLists to print to file though :(

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Notebook book = new Notebook();
		
		Note note1 = new Note();
		Tag tag1 = new Tag();
		book.myNotes.add(note1);
		book.myTags.add(tag1);
		
		book.saveAs();
		
		System.out.println("Finished.");

	}

}
package main;

import java.beans.XMLEncoder;
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.util.ArrayList;

public class Notebook implements java.io.Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;



	/* constructors */
	public Notebook (){
		id = nextId;
		nextId++;
		myTitle = "Title" + id;
	};
	
	public Notebook (String newTitle){
		id = nextId;
		nextId++;
		myTitle = newTitle;
	};
	
	
	/*	members	 */
	
	//persistent objects
	public int id;
	public static int nextId = 0;
	public String myTitle;
	
	public ArrayList<Tag> myTags = new ArrayList<Tag>();
	public ArrayList<Note> myNotes = new ArrayList<Note>();
	
	
	
	/*	methods	*/
	
	//getters & setters
	public int getID() { return id; }
	public void setID(int newID) { id = newID; }
	
	public String getMyTitle() { return myTitle; }
	public void setMyTitle(String newTitle) { myTitle = newTitle; }
	
	public ArrayList<Tag> getMyTags() { return myTags; }
	public void setMyTags(ArrayList<Tag> newTag) { myTags = newTag; }
	
	public ArrayList<Note> getMyNotes() { return myNotes; }
	public void setMyNotes(ArrayList<Note> newNotes) { myNotes = newNotes; }
	
	

	public void saveAs() {

		try {
			XMLEncoder n = new XMLEncoder(new BufferedOutputStream(
					new FileOutputStream(getMyTitle() + ".xml")));
			n.writeObject(this);
			n.close();
		} catch (Exception e) {
			System.out.println(e);
		}
	}
	
}
package main;

import java.util.ArrayList;

public class Note implements java.io.Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;



	/* constructors */
	public Note(){
		id = nextId;
		nextId++;
		
		myTitle = "Note" + id;
		myText = null;
		myParent = null;
	};
	
	public Note(String newTitle, Notebook newParent){
		
		id = nextId;
		nextId++;
		
		myTitle = newTitle;
		myText = null;
		myParent = newParent;
	};
	
	
	
	/* members */
	
	//Persistent objects
	public int id;
	public static int nextId = 0;
	
	public String myTitle;
	public String myText;
	
	public Notebook myParent;
	
	public ArrayList<Tag> myTags = new ArrayList<Tag>();
	public ArrayList<Note> myLinksFrom = new ArrayList<Note>();
	public ArrayList<Note> myLinksTo = new ArrayList<Note>();
	
	
	
	/* methods */
	
	//getters and setters
	public int getId(){return id;}
	public void setId(int newID) {id = newID;}
	
	public String getMyTitle(){return myTitle;}
	public void setMyTitle(String newTitle){myTitle = newTitle;}
	
	public String getMyText() {return myText;}
	public void setMyText(String newText) {myText = newText;}
	
	public Notebook getMyParent() {return myParent;}
	public void setMyParent(Notebook newParent){myParent = newParent;}
	
	public ArrayList<Tag> getMyTags() {return myTags;}
	public void setMyTags(ArrayList<Tag> newTags) {myTags = newTags;}
	
	public ArrayList<Note> getMyLinksFrom() {return myLinksFrom;}
	public void setMyLinksFrom(ArrayList<Note> newLinksFrom) {myLinksFrom = newLinksFrom;}
	
	public ArrayList<Note> getMyLinksTo() {return myLinksTo;}
	public void setMyLinksTo(ArrayList<Note> newLinksTo) {myLinksTo = newLinksTo;}
		
}
package main;

public class Tag implements java.io.Serializable {
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;



	/* constructors */
	public Tag(){
		id = nextId;
		nextId++;
		myTitle = null;
	};
	
	public Tag(String newTitle){
		id = nextId;
		nextId++;
		myTitle = newTitle;
	};
	
	
	/* members */
	
	//Persistent Objects
	public int id;
	public static int nextId = 0;
	public String myTitle;
	
	
	
	/* methods */
	
	//getters and setters
	public int getId(){return id;}
	public void setId(int newId){id = newId;}
	
	public String getMyTitle(){return myTitle;}
	public void setMyTitle(String newTitle){myTitle = newTitle;}

}
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0" class="java.beans.XMLDecoder">
 <object class="main.Notebook" id="Notebook0">
  <void class="main.Notebook" method="getField">
   <string>id</string>
   <void method="set">
    <object idref="Notebook0">
     <void class="main.Notebook" method="getField">
      <string>myTitle</string>
      <void method="set">
       <object idref="Notebook0"/>
       <string>Title0</string>
      </void>
     </void>
    </object>
    <int>0</int>
   </void>
  </void>
 </object>
</java>

Edit:
I changed my main method to use the get/set methods for my classes, and I now have more xml output - does it look correct, though?

//new main

package main;

public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Notebook book = new Notebook();
		
		Note note1 = new Note();
		Tag tag1 = new Tag();
		book.getMyNotes().add(note1);
		book.getMyTags().add(tag1);
		
		book.saveAs();
		
		System.out.println("Finished.");

	}

}
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0" class="java.beans.XMLDecoder">
 <object class="main.Notebook">
  <void property="ID">
   <int>0</int>
  </void>
  <void property="myNotes">
   <void method="add">
    <object class="main.Note">
     <void property="id">
      <int>0</int>
     </void>
     <void property="myTitle">
      <string>Note0</string>
     </void>
    </object>
   </void>
  </void>
  <void property="myTags">
   <void method="add">
    <object class="main.Tag">
     <void property="id">
      <int>0</int>
     </void>
    </object>
   </void>
  </void>
  <void property="myTitle">
   <string>Title0</string>
  </void>
 </object>
</java>

Edited 5 Years Ago by Duki: n/a

The final XML shows an instance of Note being added to myNotes, and an instance of Tag being added to myTags, so that all looks correct to me. You need some larger body of test data to confirm fully.

<void property="myNotes">       the arraylist
<void method="add">             add method to add to arraylist
<object class="main.Note">      what to add - a Note
<void property="id">            the Note's ID is
<int>0</int>                    0
</void>
<void property="myTitle">       and its title is
<string>Note0</string>          Note0

ps: The XML is actually a program which, when interpreted by the decoder, specifies objects to create and the set/add methods to populate them with the right values. It's pretty understandable if you just ignore all the <void> tags and read it as a series of new and set/add method calls.

This article has been dead for over six months. Start a new discussion instead.