All Downloads are FREE. Search and download functionalities are using the official Maven repository.

hm.binkley.dao.SimpleDAO Maven / Gradle / Ivy

There is a newer version: 6
Show newest version
package hm.binkley.dao;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.support.MetaDataAccessException;
import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import static org.springframework.jdbc.support.JdbcUtils.extractDatabaseMetaData;

/**
 * A very simple DAO wrapper for using Spring transactions and JDBC template, designed for lambda
 * use.  Example:
 *
 * 
 * SimpleDAO<String> someColumn = new SimpleDAO(transactionManager);
 * String columnValue = someColumn.dao(
 *        (jdbcTemplate, status) -> jdbcTemplate.queryForObject("sql here", String.class);
* * @author B. K. Oxley (binkley) */ public class SimpleDAO { private final DataSourceTransactionManager transactionManager; /** * Constructs a new {@code SimpleDAO} with the given data source transactionManager. * * @param transactionManager the transaction manager, never missing */ @Inject public SimpleDAO(@Nonnull final DataSourceTransactionManager transactionManager) { this.transactionManager = transactionManager; } /** * Access to the underlying transaction manager. * * @return the transaction manager, never missing */ @Nonnull public final DataSourceTransactionManager getTransactionManager() { return transactionManager; } /** * Gets JDBC URL for this transaction manager. This uses two connections, managed within. * * @return the JDBC URL or {@code null} if not applicable for the data source * * @throws DataAccessException if JDBC fails * @throws MetaDataAccessException if JDBC database metadata fails */ @Nullable public String getJdbcUrl() throws DataAccessException, MetaDataAccessException { return (String) extractDatabaseMetaData(transactionManager.getDataSource(), DatabaseMetaData::getURL); } /** * Runs the given dao within Spring transaction. * * @param dao the dao callback, never missing * @param the return type of the callback * * @return the callback result */ public final T dao(@Nonnull final Dao dao) { return dao.using(transactionManager); } /** * Runs the given dao within Spring transaction, requiring 0 or 1 results. * * @param dao the dao callback, never missing * @param wrongSize the exception factory for 2 or more results, never missing * @param the return type of the callback * * @return an optional of the return * * @throws DataAccessException if the results are the wrong size */ public final Optional daoMaybe(@Nonnull final Dao> dao, @Nonnull final Function wrongSize) { final List result = dao(dao); final int size = result.size(); switch (size) { case 0: return Optional.empty(); case 1: return Optional.of(result.get(0)); default: throw wrongSize.apply(size); } } /** * The functional interface for {@link #dao(Dao)}. * * @param the callback return type */ @FunctionalInterface public interface Dao { /** * Manages the JDBC callback, wrapping it in a Spring transaction. The JDBC template passed * to the callback shares the data source of the transaction manager, and executes within a * transaction template. Calls {@link #with(JdbcTemplate, TransactionStatus) with} to * execute JDBC methods. * * @param transactionManager the transaction manager, never missing * * @return the callback result * * @throws DataAccessException if JDBC fails */ default T using(@Nonnull final DataSourceTransactionManager transactionManager) throws DataAccessException { return new TransactionTemplate(transactionManager).execute(status -> { final JdbcTemplate jdbcTemplate = new JdbcTemplate( transactionManager.getDataSource()); try { return with(jdbcTemplate, status); } catch (final SQLException e) { throw jdbcTemplate.getExceptionTranslator().translate(task(), sql(), e); } }); } /** * Executes the callback, passing in the given jdbcTemplate and transaction * status. This is typically implemented as a lambda. * * Exceptions are translated into {@link DataAccessException} instances in {@link * #using(DataSourceTransactionManager) using}. * * @param jdbcTemplate the JDBC template, never missing * @param status the transaction status, never missing * * @return the callback result * * @throws SQLException if JDBC fails */ T with(@Nonnull final JdbcTemplate jdbcTemplate, @Nonnull final TransactionStatus status) throws SQLException; /** * Names the task for the Spring JDBC exception translator for more descriptive error * messages. Defaults to {@code null}. Implementors return a non-{@code * null} values, relying on the default otherwise. * * @return the task name * * @see SQLExceptionTranslator#translate(String, String, SQLException) */ default String task() { return null; } /** * Provides the executed SQL for the Spring JDBC exception translator for more descriptive * error messages. Defaults to {@code null}. Implementors return a * non-{@code null} values, relying on the default otherwise. * * @return the executed SQL * * @see SQLExceptionTranslator#translate(String, String, SQLException) */ default String sql() { return null; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy