Over a million developers have joined DZone.
Platinum Partner

Java Easy Persistent Layer - JEPLayer

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

JEPLayer is simple persistent ORM API on top of JDBC based on interceptor listeners.

http://jeplayer.googlecode.com

JPLayer is open source Apache v2 licensed.

Why another JDBC based tool?

JEPLayer was born to provide

  1. A simple API to avoid the tedious tasks of JDBC
  2. Several optional listeners to fully customize the lifecycle of JDBC persistence
  3. Methods to build simple and complex DAOs
  4. An extremely simple, automatic, configurable and error-free way to demarcate transactions
  5. Does not replace JDBC, instead of this, JDBC objects are exposed when required
  6. Ever using PreparedStatement, ever secure
  7. PreparedStatement objects are automatically cached and reused

What is different in JEPLayer

JEPLayer is simpler than Spring’s JdbcTemplate and has similar power, the persistent lifecycle can be fully configurable providing more interception points, it does not try to replace JDBC and JDBC transactions are built-in.

JEPLayer is programmatic instead of the declarative path of iBatis/MyBatis2.

JEPLayer allows getting the most of the database with no performance penalty and no waste of control typical of transparent persistence of ORMs.

Example of simple calls (MySQL)

DataSource ds = ...;
JEPLDataSource jds = new JEPLBoot().createJEPLDataSource(ds);
JEPLDAL dal = jds.createJEPLDAL();
dal.executeUpdate("DROP TABLE IF EXISTS PERSON");
dal.executeUpdate("DROP TABLE IF EXISTS COMPANY");
dal.executeUpdate("DROP TABLE IF EXISTS CONTACT");
dal.executeUpdate(
"CREATE TABLE CONTACT (" +
" ID INT NOT NULL AUTO_INCREMENT," +
" EMAIL VARCHAR(255) NOT NULL," +
" NAME VARCHAR(255) NOT NULL," +
" PHONE VARCHAR(255) NOT NULL," +
" PRIMARY KEY (ID)" +
")" +
"ENGINE=InnoDB"
);

A simple DAO

public class Contact 
{
protected int id;
protected String name;
protected String phone;
protected String email;
public Contact(int id, String name, String phone, String email)
{
this.id = id;
this.name = name;
this.phone = phone;
this.email = email;
}
public Contact() { }
/* ... gets and sets ... */
}
public class ContactDAO extends JEPLDAOBase<Contact> implements JEPLResultSetDAOListener<Contact>
{

public ContactDAO(JEPLDataSource ds)
{
super(ds);
}

@Override
public void setupJEPLResultSet(JEPLResultSet jrs, JEPLTask task) throws SQLException
{
}

@Override
public Contact createObject(JEPLResultSet jrs) throws SQLException
{
return new Contact();
}

@Override
public void fillObject(Contact obj, JEPLResultSet jrs) throws SQLException
{
ResultSet rs = jrs.getResultSet();
obj.setId(rs.getInt("ID"));
obj.setName(rs.getString("NAME"));
obj.setPhone(rs.getString("PHONE"));
obj.setEmail(rs.getString("EMAIL"));
}

public void insert(Contact contact)
{
int key = insert("INSERT INTO CONTACT (EMAIL, NAME, PHONE) " + "VALUES (?, ?, ?)",
int.class, contact.getEmail(), contact.getName(), contact.getPhone());
contact.setId(key);
}

public void update(Contact contact)
{
executeUpdateOne("UPDATE CONTACT SET EMAIL = ?, NAME = ?, PHONE = ? WHERE ID = ?",
contact.getEmail(), contact.getName(), contact.getPhone(), contact.getId());
}

public boolean delete(Contact obj)
{
return deleteById(obj.getId());
}

public boolean deleteById(int id)
{
// Only if there is no "inherited" rows or declared ON DELETE CASCADE
return executeUpdateZeroOrOne("DELETE FROM CONTACT WHERE ID = ?", id);
}

public int deleteAll()
{ // Only if "inherited" tables are empty or declared ON DELETE CASCADE
return executeUpdate("DELETE FROM CONTACT");
}

public List<Contact> selectAll()
{
return selectList("SELECT * FROM CONTACT");
}

public JEPLResultSetDAO<Contact> selectAllResultSetDAO()
{
return selectResultSetDAO("SELECT * FROM CONTACT");
}

public Contact selectById(int id)
{
return selectOneById("SELECT * FROM CONTACT WHERE ID = ?", id);
}

public List<Contact> selectByNameAndEMail(String name, String email)
{
return selectList("SELECT * FROM CONTACT WHERE NAME = ? AND EMAIL = ?", name, email);
}

public int selectCount()
{
return selectOneRowAndField("SELECT COUNT(*) FROM CONTACT", int.class);
}
}

 

A more complex method added to this DAO to provide "on the fly" limitation of the results

    public List<Contact> selectAllStatementListenerMaxRows(final int maxRows)
{
JEPLPreparedStatementListener<List<Contact>> listener = new JEPLPreparedStatementListener<List<Contact>>()
{
public void setupJEPLPreparedStatement(JEPLPreparedStatement jstmt, JEPLTask<List<Contact>> task) throws SQLException
{
PreparedStatement stmt = jstmt.getPreparedStatement();
int old = stmt.getMaxRows();
stmt.setMaxRows(maxRows);
try
{
List<Contact> res = task.exec();
}
finally
{
stmt.setMaxRows(old); // Restore
}
}
};
return selectList("SELECT * FROM CONTACT",listener);
}

 

Another method to load results between two specified rows

    public List<Contact> selectAllExplicitResultSetListenerRange(final int from,final int to)
{
JEPLResultSetDAOListener<Contact> listener = new JEPLResultSetDAOListener<Contact>()
{
@Override
public void setupJEPLResultSet(JEPLResultSet jrs, JEPLTask task) throws SQLException
{
ResultSet rs = jrs.getResultSet();
rs.absolute(from);
}

@Override
public Contact createObject(JEPLResultSet jrs) throws SQLException
{
return ContactDAO.this.createObject();
}

@Override
public void fillObject(Contact obj, JEPLResultSet jrs) throws SQLException
{
ContactDAO.this.fillObject(obj, jrs);
ResultSet rs = jrs.getResultSet();
int row = rs.getRow(); // Now returned value is the "next row"
if (row == to) jrs.stop();
}
};
return selectList("SELECT * FROM CONTACT",listener);
}

Grouping persistent actions (the Connectionis got in the beginning from DataSource and released in the end).

    final JEPLDataSource jds = ...;
JEPLTask<Contact> task = new JEPLTask<Contact>()
{
@Override
public Contact exec() throws SQLException
{
Contact contact = new Contact();
contact.setName("A Contact object");
contact.setPhone("9999999");
contact.setEmail("contact@world.com");
ContactDAO dao = new ContactDAO(jds);
dao.insert(contact);
Contact contact2 = dao.selectById(contact.getId());
return contact2;
}
};
Contact contact = jds.exec(task);

Of course with a simple boolean (autoCommit=false)  the same code is executed into a JDBC transaction

The transaction is automatically commited in the end or rollbacked on error.

    final JEPLDataSource jds = ...;
JEPLTask<Contact> task = new JEPLTask<Contact>()
{
@Override
public Contact exec() throws SQLException
{
...
}
};
Contact contact = jds.exec(task, false );

Maybe you want more control of the transaction lifecycle

    JEPLDataSource jds = ...;
JEPLTask<Contact> task = new JEPLTask<Contact>() { ... };
jds.exec(task,new JEPLConnectionListener()
{
public void setupJEPLConnection(JEPLConnection con,JEPLTask task) throws SQLException
{
con.getConnection().setAutoCommit(false); // transaction
try
{
task.exec();
con.getConnection().commit();
}
catch(Exception ex)
{
con.getConnection().rollback();
throw new SQLException(ex);
}
}
}
);

Sometimes you may want an alive ResultSet-like object returning user defined data model objects loaded on demand from DB

Adding to ContactDAO this method:

public JEPLResultSetDAO<Contact> selectAllResultSetDAO() 
{
return selectResultSetDAO("SELECT * FROM CONTACT");
}

Now this code is possible (inside a JEPLTask):   

    ContactDAO dao = ...; 
JEPLResultSetDAO<Contact> resSetDAO = dao.selectAllResultSetDAO();
if (resSetDAO.isClosed()) throw new JEPLException("WRONG");
while(resSetDAO.next())
{
Contact contact = resSetDAO.getObject();
System.out.println("Contact: " + contact.getName());
}
// Now we know is closed
if (!resSetDAO.isClosed()) throw new JEPLException("WRONG");

And  fortunately JEPLResultSetDAO is also a List loading objects on demand

    ContactDAO dao = ...; 
List<Contact> resSetDAO = dao.selectAllResultSetDAO();
if (((JEPLResultSetDAO)resSetDAO).isClosed()) throw new JEPLException("WRONG");
for(Contact contact : resSetDAO) // Uses Iterator<Contact>
{
System.out.println("Contact: " + contact.getName());
}
// Now we know is closed
if (!((JEPLResultSetDAO)resSetDAO).isClosed()) throw new JEPLException("WRONG");

The Reference Manual shows an example of three classes/tables with inheritance without a column discriminator.

Enjoy.

 

 

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}