First go at QueryRunner and Factory<Connection> arg for QueryMapper
parent
09c114e106
commit
a22109f31c
@ -0,0 +1,10 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Created by mopar on 7/1/17.
|
||||
*/
|
||||
public interface Factory<T> {
|
||||
T create() throws SQLException;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import com.moparisthebest.jdbc.codegen.JdbcMapper;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||
|
||||
|
||||
/**
|
||||
* Created by mopar on 6/30/17.
|
||||
*/
|
||||
public class QueryRunner<T extends JdbcMapper> {
|
||||
|
||||
private final Factory<T> factory;
|
||||
|
||||
public QueryRunner(final Factory<T> factory) {
|
||||
if(factory == null)
|
||||
throw new NullPointerException("factory must be non-null");
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
public <E> E run(final Runner<T, E> query) throws SQLException {
|
||||
if(query == null)
|
||||
throw new NullPointerException("query must be non-null");
|
||||
T dao = null;
|
||||
try {
|
||||
dao = factory.create();
|
||||
return query.run(dao);
|
||||
} finally {
|
||||
tryClose(dao);
|
||||
}
|
||||
}
|
||||
|
||||
public <E> E runInTransaction(final Runner<T, E> query) throws SQLException {
|
||||
if(query == null)
|
||||
throw new NullPointerException("query must be non-null");
|
||||
T dao = null;
|
||||
try {
|
||||
dao = factory.create();
|
||||
dao.getConnection().setAutoCommit(false);
|
||||
final E ret = query.run(dao);
|
||||
dao.getConnection().commit();
|
||||
return ret;
|
||||
} catch (final Throwable e) {
|
||||
if (dao != null) {
|
||||
try {
|
||||
dao.getConnection().rollback();
|
||||
} catch(SQLException excep) {
|
||||
// ignore to throw original
|
||||
}
|
||||
}
|
||||
if(e instanceof SQLException)
|
||||
throw (SQLException) e;
|
||||
if(e instanceof RuntimeException)
|
||||
throw (RuntimeException) e;
|
||||
throw new RuntimeException("odd error should never happen", e);
|
||||
} finally {
|
||||
if (dao != null) {
|
||||
try {
|
||||
dao.getConnection().setAutoCommit(true);
|
||||
} catch(SQLException excep) {
|
||||
// ignore
|
||||
}
|
||||
tryClose(dao);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Runner<T, E> {
|
||||
E run(T dao) throws SQLException;
|
||||
}
|
||||
}
|
@ -1,24 +1,107 @@
|
||||
package com.moparisthebest.jdbc.codegen;
|
||||
|
||||
import com.moparisthebest.jdbc.Factory;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Created by mopar on 5/24/17.
|
||||
*/
|
||||
public abstract class JdbcMapperFactory {
|
||||
public class JdbcMapperFactory<T> implements Factory<T> {
|
||||
|
||||
static final String SUFFIX = "Bean";
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Class<? extends T> getImplementationClass(final Class<T> jdbcMapper) throws ClassNotFoundException {
|
||||
return (Class<? extends T>) Class.forName(jdbcMapper.getName() + SUFFIX);
|
||||
}
|
||||
|
||||
public static <T> Constructor<? extends T> getConnectionConstructor(final Class<T> jdbcMapper) throws ClassNotFoundException, NoSuchMethodException {
|
||||
return getImplementationClass(jdbcMapper).getConstructor(Connection.class);
|
||||
}
|
||||
|
||||
public static <T> Constructor<? extends T> getDefaultConstructor(final Class<T> jdbcMapper) throws ClassNotFoundException, NoSuchMethodException {
|
||||
return getImplementationClass(jdbcMapper).getConstructor();
|
||||
}
|
||||
|
||||
public static <T> Constructor<? extends T> getFactoryConstructor(final Class<T> jdbcMapper) throws ClassNotFoundException, NoSuchMethodException {
|
||||
return getImplementationClass(jdbcMapper).getConstructor(Factory.class);
|
||||
}
|
||||
|
||||
public static <T> T create(final Class<T> jdbcMapper, final Connection connection) {
|
||||
try {
|
||||
return (T) Class.forName(jdbcMapper.getName() + SUFFIX).getConstructor(Connection.class).newInstance(connection);
|
||||
return getConnectionConstructor(jdbcMapper).newInstance(connection);
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T create(final Class<T> jdbcMapper) {
|
||||
return create(jdbcMapper, null);
|
||||
try {
|
||||
return getDefaultConstructor(jdbcMapper).newInstance();
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
}
|
||||
}
|
||||
|
||||
private final Constructor<? extends T> constructor;
|
||||
private final Object[] args;
|
||||
|
||||
public JdbcMapperFactory(final Class<T> jdbcMapper) {
|
||||
try {
|
||||
this.constructor = getDefaultConstructor(jdbcMapper);
|
||||
this.args = null;
|
||||
} catch (Throwable e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
}
|
||||
}
|
||||
|
||||
public JdbcMapperFactory(final Constructor<? extends T> constructor, final Object... args) {
|
||||
if(constructor == null)
|
||||
throw new NullPointerException("constructor must be non-null");
|
||||
this.constructor = constructor;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public JdbcMapperFactory(final Class<T> queryMapperClass, final Factory<Connection> connectionFactory) {
|
||||
if(queryMapperClass == null)
|
||||
throw new NullPointerException("queryMapperClass must be non-null");
|
||||
if(connectionFactory == null)
|
||||
throw new NullPointerException("connectionFactory must be non-null");
|
||||
try {
|
||||
this.constructor = queryMapperClass.getConstructor(Factory.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("queryMapperClass must have a constructor that takes Factory<Connection>", e);
|
||||
}
|
||||
this.args = new Object[]{connectionFactory};
|
||||
}
|
||||
|
||||
public JdbcMapperFactory(final Class<T> queryMapperClass, final String jndiName) {
|
||||
if(queryMapperClass == null)
|
||||
throw new NullPointerException("queryMapperClass must be non-null");
|
||||
if(jndiName == null)
|
||||
throw new NullPointerException("jndiName must be non-null");
|
||||
try {
|
||||
this.constructor = queryMapperClass.getConstructor(String.class);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException("queryMapperClass must have a constructor that takes String", e);
|
||||
}
|
||||
this.args = new Object[]{jndiName};
|
||||
}
|
||||
|
||||
@Override
|
||||
public T create() throws SQLException {
|
||||
try {
|
||||
return this.constructor.newInstance(args);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException("could not create JdbcMapper, did the processor run at compile time?", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,62 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import com.moparisthebest.jdbc.codegen.JdbcMapperFactory;
|
||||
import com.moparisthebest.jdbc.dto.Person;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static com.moparisthebest.jdbc.QueryMapperTest.*;
|
||||
|
||||
/**
|
||||
* Created by mopar on 7/1/17.
|
||||
*/
|
||||
public class QueryRunnerTest {
|
||||
public static final QueryRunner<QueryMapper> qr = new QueryRunner<QueryMapper>(new JdbcMapperFactory<QueryMapper>(QueryMapper.class, new Factory<Connection>() {
|
||||
@Override
|
||||
public Connection create() throws SQLException {
|
||||
return QueryMapperTest.getConnection();
|
||||
}
|
||||
}));
|
||||
|
||||
private void testPerson(final Person expected, final String query) throws Throwable {
|
||||
final Person actual = qr.runInTransaction(new QueryRunner.Runner<QueryMapper, Person>() {
|
||||
@Override
|
||||
public Person run(final QueryMapper qm) throws SQLException {
|
||||
return qm.toObject(query, expected.getClass(), expected.getPersonNo());
|
||||
}
|
||||
});
|
||||
/*
|
||||
System.out.println("expected: " + expected);
|
||||
System.out.println("actual: " + actual);
|
||||
*/
|
||||
Assert.assertEquals(expected, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldRegularPerson() throws Throwable {
|
||||
testPerson(fieldPerson1, personRegular);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldRegularAndUnderscore() throws Throwable {
|
||||
testPerson(fieldBoss1, bossRegularAndUnderscore);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldRegularAndUnderscoreReverse() throws Throwable {
|
||||
testPerson(fieldBoss1, bossRegularAndUnderscoreReverse);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldRegular() throws Throwable {
|
||||
testPerson(fieldBoss2, bossRegular);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFieldUnderscore() throws Throwable {
|
||||
testPerson(fieldBoss3, bossUnderscore);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue