Java Ultra-Lite Persistence (JULP)
Features
- Open Source (Apache Software License v2)
- Running both in container and stand-alone
- Small footprint (~300KB)
- Database independent (tested so far with Oracle, Sybase ASE, MckoiDB, hsqldb)
- Inheritance
- Many classes per table
- Many tables per class
- Batch UPDATEs/INSERTs/DELETEs
- Generates UPDATEs only for actually modified fields
- Lazy loading
PreparedStatement
s/Statement
s caching
- DELETE/INSERT instead of UPDATE (useful in some cases)
- Simple mappings: the only mapping you need is <catalog >.<schema>.table.column=fieldName
CREATE TABLE PRODUCT(PRODUCT_ID INTEGER NOT NULL PRIMARY KEY, NAME VARCHAR, PRICE DECIMAL)
...
public class Product{
Integer productId;
String productName;
double price;
...
}
...
ProductFactory factory = new ProductFactory(Product.class);
Map mapping = new HashMap();
mapping.put("PRODUCT.PRODUCT_ID", "productId");
mapping.put("PRODUCT.NAME", "productName");
mapping.put("PRODUCT.PRICE", "price");
factory.setMapping(mapping);
...
It is entirely up to you where would you get the values from:
you can get them from .xml, .properties, JNDI, database. You can even hardcoded them (just don't say I recommended this ;-) )
- Instead of sending for updates over the network all the objects, it's possible to send only modified objects.
It's also possible to generate DML statements on the client and send them along with parameters to Application Server or another application for processing:
...
ProductFactory factory = new ProductFactory(Product.class);
((DBDataWriter) factory.getDataWriter()).setGenerateSQLOnly(true);
...
factory.writeData();
...
List allChanges = ((DBDataWriter) factory.getDataWriter()).getGeneratedSQL();
//Another way...
...
Object[] changes = (Object[]) allChanges.get(0);
String sql = (String) changes[0];
Object arg = changes[1];
PreparedStatement ps = connection.prepareStatement(sql, arg);
...
Or if you'd use JULP for updates:
DBServices dbServices = new DBServices();
...
dbServices.execute(sql, arg);
- Very simple way to populate objects from database:
...
ProductFactory factory = new ProductFactory(Product.class);
ResultSet rs = ...;
factory.load(new Wrapper(rs));
List<Product> products = this.getObjects();
...
It is entirely up to you where would you get the ResultSet from:
it could be another framework, hand-written sql, etc. It means the full power of SQL in your hands and not limited by framework's API.
However there are convinient methods available:
...
ProductFactory factory = new ProductFactory(Product.class);
List arg = new ArrayList();
arg.add(new Double(77.50));
arg.add("%CARD%");
String sql = "SELECT * FROM PRODUCT WHERE PRICE > ? AND NAME LIKE ?";
DBServices dbServices = new DBServices();
...
factory.load(new Wrapper(dbServices.getResultSet(sql, arg)));
dbServices.release(true);
List<Product> products = this.getObjects();
...
Usually I keep sql in .properties or .xml files and add WHERE clause based on users selection.
There are several objects in JULP which give you some convinient methods to do that.
- Running in disconnected mode: You can populate your objects from database or any other source, modify them, create new ones
and then serialize them. Later you can restore them, connect to database or send the objects to application server and apply the changes.
- Ability to persist POJO (Plain Java Objects): Yes, you need to extend
org.julp.AbstractDomainObject
, however this is not the only way.
If your objects do not implement org.julp.DomainObject
or do not extend org.julp.AbstractDomainObject
then they will be enchance in run-time
using cglib/asm libraries.
- Generating UPDATE only for the columns which has been changed
- Optimistic concurrency locking: WHERE clause for UPDATE and DELETE is generated using settings:
OptimisticLock.KEY_COLUMNS
OptimisticLock.KEY_AND_MODIFIED_COLUMNS
OptimisticLock.KEY_AND_UPDATEBLE_COLUMNS
It means even if a table has no TIMESTAMP or DATETIME or version column it's still possible to use Optimistic concurrency locking.
- Data Modification Sequence: when you modify many objects once, you can specify order of modification,
for example you can specify to do DELETEs first, then UPDATEs, then INSERTs (any order or skip any of them)
...
ProductFactory factory = new ProductFactory(Product.class);
...
DataModificationSequence[] dataModificationSequence = new DataWriter.DataModificationSequence[3];
dataModificationSequence[0] = DataWriter.DataModificationSequence.DATA_MODIFICATION_SEQUENCE_DELETE;
dataModificationSequence[1] = DataWriter.DataModificationSequence.DATA_MODIFICATION_SEQUENCE_UPDATE;
dataModificationSequence[2] = DataWriter.DataModificationSequence.DATA_MODIFICATION_SEQUENCE_INSERT;
factory.setDataModificationSequence(dataModificationSequence);
This will disable INSERTs and DELETEs:
DataWriter.DataModificationSequence[] updateOnly = new DataWriter.DataModificationSequence[1];
updateOnly[0] = DataWriter.DataModificationSequence.DATA_MODIFICATION_SEQUENCE_UPDATE;
((DBDataWriter) dataWriter).setDataModificationSequence(updateOnly);
- You can append results of SELECT to object list instead of replacing previous result, just convenient method, works like UNION ALL
- Pagination support: you can send to client or display just certain number of records:
...
ProductFactory factory = new ProductFactory(Product.class);
...
factory.load(...
...
Pager pager = new Pager(factory.getObjectList());
pager.setPageSize(20);
PageHolder page = pager.getPage(1);
System.out.println("\nTotal records: " + page.getObjectsTotal() + ", Page " + page.getPageNumber() + " of " + page.getPagesTotal() + "\n");
Iterator iter = page.getPage().iterator();
while (iter1.hasNext()){
Product product = (Product) iter.next();
System.out.println(product);
}
...
- JULP is based on DAO pattern, so if some day you will decide to move to another framework/library it should be relatively simple.
- There are some objects/utilities which can be usable for development with/without JULP.
The most useful are org.julp.gui.generator.ResultSet2JavaObjectsGenerator
and org.julp.gui.generator.GeneratorFrame
.
This objects allow to create DomainObject
s, mappings and optionally html/swing forms from command line or visually from SELECT
statement.
- Dependencies:
- ASM
- CGLIB
- JExcelAPI
- TableLayout
Note: JExcelAPI and TableLayout are needed only for using with optional Swing components
- More...