Thursday, July 15, 2010

Java XML Persistence with XStream

Database is usually used to persist data as it provides flexible query, high performance and other powerful functions. In Java, there are JDBC, in the low level operation with SQL and Java Persistence API aiming object level solution. But they are too heavy when we only need simple data persistence without complicated query requirement. In this scenario, XML seems to be the best choice, plus XStream, provides a light weight and convenience persistence alternative. In this post, I will show you how easy to use XStream implement basic CRUD operation against XML storage.



The Model


I define a Identiable interface to get Id(primary key) from model. The id can be String, Long or Integer.
public interface Identiable {
 public Object getId();
}

I will use Book(isbn is the primary key) as example:
import com.thoughtworks.xstream.annotations.XStreamAlias;

@XStreamAlias("book")
public class Book implements Identiable {

 @XStreamAlias("isbn")
 private String isbn;

 @XStreamAlias("booktitle")
 private String title;

 @XStreamAlias("description")
 private String description;

 .... Getter and Setter....
      
 @Override
 public Object getId() {
  return this.getIsbn();
 }

I use annotation @XStreamAlias("isbn") to format the xml elment name. Here is what the serialized xml looks like:


  1847199747
  Spring Security 3
  
SECURE YOUR WEB APPLICATIONS AGAINST MALICIOUS INTRUDERS WITH THIS EASY TO FOLLOW PRACTICAL GUIDE 



The XMLPersistence Basic

XmlPersistence implements the basic CRUD operation.

import java.io.File;
import java.util.Collection;

import com.thoughtworks.xstream.persistence.FilePersistenceStrategy;
import com.thoughtworks.xstream.persistence.PersistenceStrategy;
import com.thoughtworks.xstream.persistence.XmlMap;

public class XmlPersistence {

 private XmlMap xmlMap;

 /**
  * 
  * @param dir where xml files persist
  */
 public XmlPersistence(String dir) {
  PersistenceStrategy strategy = new FilePersistenceStrategy(
    new File(dir));
  xmlMap = new XmlMap(strategy);
 }

 public void save(Identiable entity) {

  xmlMap.put(entity.getId(), entity);
 }

 public Identiable retrive(Identiable entity) {
  return (Identiable) xmlMap.get(entity.getId());
 }

 public void update(Identiable entity) {

  xmlMap.put(entity.getId(), entity);
 }

 public void delete(Identiable entity) {

  xmlMap.remove(entity.getId());
 }

 @SuppressWarnings("unchecked")
 public Collection getAll() {
  return xmlMap.values();
 }

 

}

How to use


//save xml files in "xml" directory
XmlPersistence xmlDao = new XmlPersistence("xml");

//Create
xmlDao.save(this.getBook1());
xmlDao.save(this.getBook2());


//Reterive
Book book = (Book) xmlDao.retrive(getBook1());

//Update
Book book1 = this.getBook1();
book1.setDescription(book1.getDescription().toUpperCase());

xmlDao.update(book1);

//Delete
xmlDao.delete(this.getBook1());
//Iterate 
Collection all = xmlDao.getAll();
  
  for (Identiable entity : all) {
   Book book = (Book) entity;

   System.out.println(book);

 }


//test data
private Book getBook1() {

  Book book = new Book();

  book.setTitle("Spring Security 3");
  book.setIsbn("1847199747");
  book.setDescription("Secure your web applications against malicious intruders with this easy to follow practical guide ");
  return book;
 }

 private Book getBook2() {

  Book book = new Book();

  book.setTitle("Lucene in Action");
  book.setIsbn("1933988177");
  book.setDescription("with clear writing, reusable examples, and unmatched advice on best practices, Lucene in Action, Second Edition is still the definitive guide to developing with Lucene.");
  return book;
 }

XStream will generated xml file for each object:


XStream is only 401K and it only depends on xpp3, just 24.3K.

6 comments:

Josep LluĂ­s Prat said...

I use XStream in my projects to store objects in XML format. It's very powerful and very easy to use.
The only but, is that it's not so easy to support namespaces.

Tony said...

I used to use XStream for just about all Java object marshalling, but over time I just found it too limiting. JAXB is my choice now. JAXB is almost as easy to use as XStream and is also tightly integrated into other Java standards like JAX-RS. Check it out if you haven't already.

Nikola Valentinov Petrov said...

Maybe it is a nice idea to make the XmlPersistence class generic like so:
XmlPersistence and provide a factory method like in(String dir). This way you won't clutter the code with casts all over the place.

Nikola Valentinov Petrov said...

XmlPersistance should have been

XmlPersistence<? extends Identiable>

PS: Bored of html escaping -.-

Peter said...

Thanks for using my book as the example! ;)

Cheers,
Peter
(Author, Spring Security 3)

Ke Cai said...

WOW~~~
What a honor :)
I'm reading your book. Great job, I love it.