Zero-config object persistence with Simple Persistence for Java

Out of the box object persistence for Java applications

Simple Persistence for Java is an open source object-relational persistence library that uses a custom query language and built-in database support to simplify object persistence in Java applications. In this article, software architect Sami Salkosuo introduces the library and walks you through its zero-admin, zero-config approach to object persistence.

Share:

Sami Salkosuo (sami.salkosuo@fi.ibm.com), Software Architect, IBM

author photoSami Salkosuo has worked at IBM since 1999. His main area of interest is Java programming and he is a Sun Certified Java Programmer, IBM Certified Solution Developer for XML and Related Technologies, and IBM Certified Solution Developer for IBM WebSphere Portal. Beyond Java technology, he also has experience with Python, Fortran, LabVIEW, Visual Basic, LISP, Perl, and PHP.



13 February 2007

Object persistence is a must in almost all Java™ applications, from the desktop to the enterprise. The downside of persistence is that it has never been particularly simple. But that has changed with the most recent version of Simple Persistence for Java, an open source library for object-relational persistence.

Simple Persistence for Java version 2.1.0 adds support for HSQLDB, a 100% pure Java database. Neither Simple Persistence for Java nor HSQLDB requires administration or configuration from the application user. Taken together, these tools enable you to introduce persistence to your applications with very little work.

This article introduces you to Simple Persistence for Java v2.1.0 and shows you how to use it to achieve almost effortless object persistence in your Java applications.

Simple Persistence for Java

Simple Persistence for Java is an open source library that has been licensed under LGPL, developed internally by the Hungarian company NetMind Consulting, and released to the open source community.

Many object-relational libraries are available to Java developers. Simple Persistence for Java differs from other libraries in that you can use it with zero configuration. One of the main design principles of this library is that it requires no configuration files, no XML mapping files, and no properties to configure. (Provided you have a suitable database, of course.)

The Simple Persistence for Java library also has the following important features:

  • Small footprint (135KB)
  • Simple API
  • Support for multiple databases
  • Simple query language
  • Polymorphism
  • Lazy result list

With version 2.1.0, support for the HSQLDB database was added to the Simple Persistence for Java library. HSQLDB is an open source, lightweight, pure-Java SQL database engine, licensed under a BSD-style license. HSQLDB supports a rich subset of ANSI-92 SQL and also SQL 99 and 2003 enhancements. It offers memory- and disk-based tables and supports embedded and server operation modes.


The StockData application

I use a sample program called StockData to show you how easy object persistence can be with the Simple Persistence for Java library and HSQLDB. StockData filters historical stock data (in a CSV file) based on user queries. The program operates with an embedded database and is run from a command line.

You may want to reproduce my development environment and set up the sample application for yourself to follow the discussion. The development environment for the StockData is Eclipse 3.2.1, and the minimum Java version is JDK 1.5.0. I've started the HSQLDB database in embedded mode using the memory-based database option. Note that I could have chosen a disk-based embedded database or a server-side database. I've chosen to use the HSQLDB memory-based database for demonstration purposes.

The following libraries are required to execute the StockData sample program:

  • commons-io-1.2.jar
  • commons-logging-api.jar
  • commons-logging.jar
  • hsqldb.jar
  • java-cup-11-runtime.jar
  • log4j-1.2.8.jar
  • netmind-persistence-2.1.0.jar

The StockData program uses commons-io and commons-logging packages and HQSLSB is not dependent on any jars. The netmind-persistence-2.1.0.jar is dependent on java-cup-11-runtime.jar and log4j-1.2.8.jar.

Example source code

Listing 1 shows the StockData program source code:

Listing 1. StockData
public class StockData
{
  private static Log log;
  public static void main(String[] args)
  {
    System.setProperty("log4j.configuration", "file:log4j.properties");
    log = LogFactory.getLog(StockData.class);
    try
    {
      String symbol = args[0];
      String csvFile = args[1];
      String query = args[2];
      // open store, uses HSQLDB driver and memory only database
      Store store = new Store("org.hsqldb.jdbcDriver","jdbc:hsqldb:mem:stockdata");
      // read csv and generate beans
      List historicalData = FileUtils.readLines(new File(csvFile), "UTF-8");
      // remove first line (header)
      historicalData.remove(0);
      // store beans to database
      for (Object _data : historicalData)
      {
        String[] data = ((String) _data).split(",");
        StockBean bean = new StockBean(symbol, data[0],
            Double.parseDouble(data[4]), Double.parseDouble(data[5]));
        //save stock bean to database
        store.save(bean);
      }
      // find beans that match query
      List results=store.find(query);
      // print beans that matched
      System.out.println("Total results: "+results.size());
      for (Object object : results)
      {
        StockBean bean=(StockBean)object;
        System.out.println(bean.toString());
      }
    }
    catch (Exception e)
    {
      log.error(e.getMessage(), e);
      System.out
          .println("Usage: java sample.StockData " +
              "<symbol name> <historical prices file> <query>");
    }
  }
}

The StockData application uses the Apache Commons IO package to read a CSV file to a List. A for loop then parses text rows and creates StockBean objects that are stored to the database. The CSV file's format is as follows:

Date,Open,High,Low,Close,Volume,Adj. Close*
29-Dec-06,97.00,97.88,96.83,97.15,4455900,97.15
28-Dec-06,97.11,97.40,96.87,96.97,4501700,96.97
27-Dec-06,96.30,97.23,96.27,97.20,4571600,97.20

A sample CSV file is provided with the downloadable demonstration package.

After storing all objects to the database, a simple find query (specified in the command line) is executed and a List of matched results is returned. Results are printed to System.out. Note that Simple Persistence for Java implements LazyList, where objects are retrieved on demand. This ensures that you don't end up with thousands of objects stored in memory.

The StockBean object

Listing 2 shows the source code for the StockBean Java object that is used to store information in StockData. StockBean has four fields: symbol name, date, price, and volume.

Listing 2. The StockBean object
public class StockBean
{
  private String symbolName = "";
  private String date = null;
  private double price = 0.0;
  private double volume = 0.0;
  public StockBean()
  {
    // no-argument constructor required by Simple Persistence
  }
  public String toString()
  {
    StringBuffer sb=new StringBuffer();
    sb.append(symbolName);
    sb.append(',');
    sb.append(date);
    sb.append(',');
    sb.append(price);
    sb.append(',');
    sb.append(volume);
    return sb.toString();
  }
  public StockBean(String symbolName, String date, double price, double volume)
  {
    this.symbolName = symbolName;
    this.date = date;
    this.price = price;
    this.volume = volume;
  }
  public String getDate()
  {
    return date;
  }
  public void setDate(String date)
  {
    this.date = date;
  }
  public double getPrice()
  {
    return price;
  }
  public void setPrice(double price)
  {
    this.price = price;
  }
  public String getSymbolName()
  {
    return symbolName;
  }
  public void setSymbolName(String symbolName)
  {
    this.symbolName = symbolName;
  }
  public double getVolume()
  {
    return volume;
  }
  public void setVolume(double volume)
  {
    this.volume = volume;
  }
}

Elements of simplicity

As you can see from the StockData source in Listing 1, Simple Persistence for Java really does simplify object-relational persistence. You basically only need three lines of code to add persistence to your Java applications and retrieve objects from the HSQLDB:

  • The Store object constructor.
  • A save() method that saves objects to the database.
  • One or more find() methods used to retrieve objects.

The constructor is simple enough; just give your JDBC driver as the first argument and the JDBC URL as the second argument:

Store store = new Store("org.hsqldb.jdbcDriver","jdbc:hsqldb:mem:stockdata");

The Store object is later used to store and retrieve objects.

Saving objects to the database is also straightforward:

StockBean bean = new StockBean(symbol, date, price, volume);
store.save(bean);

Just calling save() stores an object to the database. Any necessary tables are created behind the scenes.

Finding objects using the query language that is used to retrieve objects is also quite easy:

List results=store.find(query);

There are four different find() methods:

  • find(String statement)
  • find(String statement, Object[] parameters)
  • findSingle(String statement)
  • findSingle(String statement, Object[] parameters)

The find() method with parameters works as in SQL, where "?" is a placeholder for a parameter object. findSingle() methods are self-explanatory.


Custom query language

One thing you probably have noted by now is that Simple Persistence for Java uses a custom query language to find objects. The query syntax is object oriented and there is no concept of tables, indices, or other typical relational-database concepts. For example, the following query returns all StockBean objects in a List:

find stockbean

Because the resulting List is lazy, you can query quite a lot of objects without affecting application performance or memory consumption. So, for example, a getSize() method would return a total number of results, even though the actual objects are retrieved on demand.

Query syntax

Simple Persistence for Java queries start with "find", with the second element being the name of the class that you want to retrieve. A fully qualified class name is required only when you have many classes with same name but a different package.

Where clauses are similar to the ones found in SQL. Typical operators such as "or", "and", "not", "<", ">", "=", "like", and so on are also supported.

The following query would return all StockBean objects whose value is between USD90 and USD92.5:

find stockbean where price>90 and price6lt;'92.5' and symbolname='IBM'

Note that you can present integer values without quotes but double and string values require quotes.

You can also order results using the same "order by" syntax found in SQL. For example, the following command orders results in descending order by price:

find stockbean where price>90 and price<'92.5' and symbolname='IBM' order by price desc

Running the example

The StockData program searches stock data in a CSV file. The downloadable package contains compiled sources and a batch file called stockdata.bat. The program syntax is stockdata.bat <symbol name> <csv file name> <find query>. You can use this syntax to query the sample application for yourself.

The results of the following command:

stockdata.bat IBM ibm_2006.csv "find stockbean where price>90 and price<'92.5' and symbolname='IBM'"

are shown in Figure 1:

Figure 1. Output from querying the StockData application
Output from querying StockData

Additional features

The StockData application demonstrates the basic features of Simple Persistence for Java. In addition, the library has some more advanced features not exposed by StockData, including polymorphism and user-managed transactions.

Polymorphism

In Simple Persistence for Java, a JavaBean that you want to store to a database can be extended from a class. For example:

public class StockBeanExt extends StockBean
{
  private int totalTrades=0;
  public StockBeanExt()
  {
    // no-argument constructor required by Simple Persistence
  }
  public int getTotalTrades()
  {
    return totalTrades;
  }
  public void setTotalTrades(int totalTrades)
  {
    this.totalTrades=totalTrades;
  }
}

After you have saved several StockBean and StockBeanExt objects, queries that target fields located in the StockBean class will return both StockBean and StockBeanExt objects.

User-managed transactions

The Simple Persistence for Java library also supports user-managed transactions, allowing you to specify when a transaction starts and commits. Take the following transaction as an example:

Transaction tx = tt.getTransaction(TransactionTracker.TX_REQUIRED);
tx.begin();
try
{
   ...operations...
} catch ( ... ) {
   ... handling code...
   tx.markRollbackOnly();
} finally {
   tx.commit();
}

Note how the finally clause includes commit. This is always executed even if there is an exception. In the catch() clause, the method markRollbackOnly() denotes that when commit() is called, it actually does rollback instead of commit.

See Resources to learn more about these and other features of the Simple Persistence for Java library v2.1.0.


In conclusion

In this article, I've introduced the Simple Persistence for Java v2.1.0 library and explained its basic features and components. I've demonstrated a simple object-persistence scenario using the library's custom query language and the HSQLDB database and also discussed some of the library's advanced features.

I've found that the Simple Persistence for Java library's straightforward API and zero-configuration approach greatly simplify object-relational persistence. If you need persistence (especially in small utility programs) but you want to avoid writing SQL, using a persistence framework, or installing a standalone database in your computer, then using Simple Persistence for Java v2.1.0 with the HSQLDB database is a viable option.


Download

DescriptionNameSize
Sample codej-sp4j.zip3KB

Resources

Learn

Get products and technologies

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=195516
ArticleTitle=Zero-config object persistence with Simple Persistence for Java
publish-date=02132007