Spring/JPA Java SQL Scalar Function Utility for Layered Applications

David Pitt Java, Spring Leave a Comment

Most Java applications interact with a relational data source through a POJO object model that is mapped with an object relational (OR) mapping framework.  Developers don’t have to worry about constructing SQL, but instead use a Java based API provided by the OR mapping framework to apply object oriented design principles to their application models.

However, in some cases, an impedance mismatch occurs between the application model and the underlying relational data model.  One such example is when a requirement calls for a summation, average, count, value from the data store, requiring an SQL expression shown below.

select sum(<column name>) from <table> where <where clause>

or

select  current_datetime from <table> where <where clause>

This results in a single value result, and as such does not readily map to an application model (POJO), but rather to an independent Java primitive type. So, where and how should this data access execution occur in a Java layered application?

How to access relational scalar values can be performed using the generalized utility shown below. It does assume that you are using the Spring framework and a JPA based O/R mapping framework, and that the Spring application is configured to auto wire a JPA entityManager.

public class ScalarFunctionDao<T> {

    @PersistenceContext
    private EntityManager entityManager;
    public T singleResult(String sql) {
        return singleResult(sql, null);
    }
    public List<T> list(String sql) {
        return list(sql, null);
    }
    public T singleResult(String sql, Object… parms) {
        List<T> result = null;
        result = list(sql, parms);
        return result.isEmpty() ? null : result.get(0);
    }
    public List<T> list(String sql, Object… parms) {
        if (parms == null || parms.length == 0) {
            return entityManager.createNativeQuery(sql).getResultList();
        }
        Query query = entityManager.createNativeQuery(sql);
        for (int i = 0; i < parms.length; i++) {
            query.setParameter(i + 1, parms[i]);
        }
        return query.getResultList();
    }
}

This utility provides a mechanism for retrieving a single type or a list of values with the return values being a generic type.
An example: service class implementation that defines methods for summing and averaging for a table column value (shown below).

@Service
public class MyService {
    @Autowired
    ScalarFunctionDao<BigDecimal> scalarDao;
    public Double sum() {
        // sum daily sales, no parameters required
        String sql = “select avg(DAILY_SALES) from STORE_TABLE where id = ?”;
        return scalarDao.singleResult(sql).doubleValue();
    }
    public Double average(Long storeId) {
        // sum average daily sales for store, storeId parameter required
        Long[] params = new Long[] { storeId };
        String sql = “select avg(DAILY_SALES) from STORE_TABLE where id = ?”;
        return scalarDao.singleResult(sql, params).doubleValue();
    }
}

As you can see in the example service implementation above, the scalar DAO utility is auto-wired with a BigDecimal type. This allows the utility to express native SQL scalar functions with and without parameters that result in Big values.

Spring’s auto-wiring capability allows multiple instances to be bound to a specific type for a more type safe implementation. The example below shows how a method can be added to obtain a current timestamp from the database.

@Service
public class MyService {
    @Autowired
    ScalarFunctionDao<BigDecimal> scalarDao;
    @Autowired
    ScalarFunctionDao<Timestamp> timestampDao;
    public Timestamp current() {
        // current timestamp
        String sql = “select current_timestamp from STORE_TABLE”;
        return timestampDao.singleResult(sql);
    }

I hope that you may find this utility useful — I sure have.

— David Pitt, asktheteam@keyholesoftware.com


About the Author
David Pitt

David Pitt

Twitter

David Pitt is a Sr. Solutions Architect and Managing Partner of Keyhole Software with nearly 25 years IT experience. Recent projects involve speaking, writing, and training developers in enterprise JavaScript​/single-page application​ development best practices​, as well as the development of GrokOla, the Q&A-based wiki software​ for development teams.​


Share this Post

Leave a Reply