Add SingletonCloseable.java and many tests for it
This commit is contained in:
parent
14d4b897ad
commit
b62dc1912a
|
@ -0,0 +1,130 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import com.moparisthebest.jdbc.codegen.JdbcMapperFactory;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This provides implementations of Closeable/JdbcMapper interfaces that simply construct a new object,
|
||||||
|
* execute the method, and close the object for each method call. Implementations returned never need
|
||||||
|
* to be closed and are as thread-safe as the Factory sent in, of which the provided impls are entirely thread-safe.
|
||||||
|
* <p>
|
||||||
|
* If any of the methods returns an *interface* that extends Closeable, we assume *this* Closeable should not be closed
|
||||||
|
* until the returned value is, and it is therefore wrapped with WrappingCloseable before return
|
||||||
|
*/
|
||||||
|
public class SingletonCloseable implements InvocationHandler {
|
||||||
|
|
||||||
|
//IFJAVA8_START
|
||||||
|
|
||||||
|
public static <T extends AutoCloseable> T of(final Class<T> jdbcMapper) {
|
||||||
|
return of(jdbcMapper, JdbcMapperFactory.of(jdbcMapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends AutoCloseable> T of(final Class<T> jdbcMapper, final String jndiName) {
|
||||||
|
return of(jdbcMapper, JdbcMapperFactory.of(jdbcMapper, jndiName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends AutoCloseable> T of(final Class<T> jdbcMapper, final Factory<? extends T> factory) {
|
||||||
|
return (T) Proxy.newProxyInstance(jdbcMapper.getClassLoader(),
|
||||||
|
new Class<?>[]{jdbcMapper}, new SingletonCloseable(factory)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Factory<? extends AutoCloseable> factory;
|
||||||
|
|
||||||
|
protected SingletonCloseable(final Factory<? extends AutoCloseable> factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
|
||||||
|
AutoCloseable jdbcMapper = null;
|
||||||
|
try {
|
||||||
|
jdbcMapper = factory.create();
|
||||||
|
Object ret = method.invoke(jdbcMapper, args);
|
||||||
|
if (ret instanceof AutoCloseable) {
|
||||||
|
// wrap jdbcMapper into ret so it gets closed when ret does, can only do this for Interfaces like ResultSet not concrete classes
|
||||||
|
final Class<?> returnType = method.getReturnType();
|
||||||
|
if (returnType.isInterface() && AutoCloseable.class.isAssignableFrom(returnType)) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
final Class<AutoCloseable> returnTypeCloseable = (Class<AutoCloseable>) returnType;
|
||||||
|
ret = WrappingCloseable.wrap((AutoCloseable) ret, returnTypeCloseable, jdbcMapper);
|
||||||
|
// now that jdbcMapper will be closed by above, don't let it be closed here
|
||||||
|
// if a ClassCastException might happen here we will leak jdbcMapper, but how could it???
|
||||||
|
jdbcMapper = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} finally {
|
||||||
|
tryClose(jdbcMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//IFJAVA8_END
|
||||||
|
|
||||||
|
/*IFJAVA6_START
|
||||||
|
|
||||||
|
public static <T extends Closeable> T of(final Class<T> jdbcMapper) {
|
||||||
|
return of(jdbcMapper, JdbcMapperFactory.of(jdbcMapper));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T extends Closeable> T of(final Class<T> jdbcMapper, final String jndiName) {
|
||||||
|
return of(jdbcMapper, JdbcMapperFactory.of(jdbcMapper, jndiName));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Closeable> T of(final Class<T> jdbcMapper, final Factory<? extends T> factory) {
|
||||||
|
return (T) Proxy.newProxyInstance(jdbcMapper.getClassLoader(),
|
||||||
|
new Class<?>[]{jdbcMapper}, new SingletonCloseable(factory)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Factory<? extends Closeable> factory;
|
||||||
|
|
||||||
|
protected SingletonCloseable(final Factory<? extends Closeable> factory) {
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
|
||||||
|
Closeable jdbcMapper = null;
|
||||||
|
try {
|
||||||
|
jdbcMapper = factory.create();
|
||||||
|
Object ret = method.invoke(jdbcMapper, args);
|
||||||
|
if (ret instanceof Closeable) {
|
||||||
|
// wrap jdbcMapper into ret so it gets closed when ret does, can only do this for Interfaces like ResultSet not concrete classes
|
||||||
|
final Class<?> returnType = method.getReturnType();
|
||||||
|
if (returnType.isInterface() && Closeable.class.isAssignableFrom(returnType)) {
|
||||||
|
@SuppressWarnings("unchecked") final Class<Closeable> returnTypeCloseable = (Class<Closeable>) returnType;
|
||||||
|
ret = WrappingCloseable.wrap((Closeable) ret, returnTypeCloseable, jdbcMapper);
|
||||||
|
// now that jdbcMapper will be closed by above, don't let it be closed here
|
||||||
|
// if a ClassCastException might happen here we will leak jdbcMapper, but how could it???
|
||||||
|
jdbcMapper = null;
|
||||||
|
}
|
||||||
|
} else if (ret instanceof ResultSet) {
|
||||||
|
// wrap jdbcMapper into ret so it gets closed when ret does, can only do this for Interfaces like ResultSet not concrete classes
|
||||||
|
final Class<?> returnType = method.getReturnType();
|
||||||
|
if (returnType.isInterface() && ResultSet.class.isAssignableFrom(returnType)) {
|
||||||
|
@SuppressWarnings("unchecked") final Class<ResultSet> returnTypeCloseable = (Class<ResultSet>) returnType;
|
||||||
|
ret = WrappingCloseable.wrap((ResultSet) ret, returnTypeCloseable, jdbcMapper);
|
||||||
|
// now that jdbcMapper will be closed by above, don't let it be closed here
|
||||||
|
// if a ClassCastException might happen here we will leak jdbcMapper, but how could it???
|
||||||
|
jdbcMapper = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} finally {
|
||||||
|
tryClose(jdbcMapper);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IFJAVA6_END*/
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.lang.reflect.InvocationHandler;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.lang.reflect.Proxy;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
|
||||||
|
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This wraps a class implementing closeable and also closes a supplied closeable after this class is closed
|
||||||
|
* <p>
|
||||||
|
* An example use is for holding a Connection open while a returned ResultSet is still held open, and closing the
|
||||||
|
* Connection when the ResultSet is closed
|
||||||
|
*/
|
||||||
|
public class WrappingCloseable implements InvocationHandler {
|
||||||
|
|
||||||
|
//IFJAVA8_START
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends AutoCloseable, C extends AutoCloseable> T wrap(final T delegate, final Class<T> iface, final C closeable) {
|
||||||
|
return (T) Proxy.newProxyInstance(iface.getClassLoader(),
|
||||||
|
new Class<?>[]{iface}, new WrappingCloseable(delegate, closeable)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Object delegate;
|
||||||
|
protected final AutoCloseable closeable;
|
||||||
|
|
||||||
|
protected WrappingCloseable(final Object delegate, final AutoCloseable closeable) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.closeable = closeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//IFJAVA8_END
|
||||||
|
|
||||||
|
/*IFJAVA6_START
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends Closeable, C extends Closeable> T wrap(final T delegate, final Class<T> iface, final C closeable) {
|
||||||
|
return (T) Proxy.newProxyInstance(iface.getClassLoader(),
|
||||||
|
new Class<?>[]{iface}, new WrappingCloseable(delegate, closeable)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static <T extends ResultSet, C extends Closeable> T wrap(final T delegate, final Class<T> iface, final C closeable) {
|
||||||
|
return (T) Proxy.newProxyInstance(iface.getClassLoader(),
|
||||||
|
new Class<?>[]{iface}, new WrappingCloseable(delegate, closeable)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Object delegate;
|
||||||
|
protected final Closeable closeable;
|
||||||
|
|
||||||
|
protected WrappingCloseable(final Object delegate, final Closeable closeable) {
|
||||||
|
this.delegate = delegate;
|
||||||
|
this.closeable = closeable;
|
||||||
|
}
|
||||||
|
|
||||||
|
IFJAVA6_END*/
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
|
||||||
|
try {
|
||||||
|
return method.invoke(delegate, args);
|
||||||
|
} finally {
|
||||||
|
// todo: is there a better way of determining close method?
|
||||||
|
if ((args == null || args.length == 0) && "close".equals(method.getName())) {
|
||||||
|
tryClose(closeable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
|
||||||
|
interface Closed extends Closeable {
|
||||||
|
|
||||||
|
boolean isClosed();
|
||||||
|
|
||||||
|
String name();
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
class SimpleCloseable implements Closed {
|
||||||
|
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
SimpleCloseable(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String name() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,198 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class SingletonCloseableTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegularCloseable() throws Exception {
|
||||||
|
final DaoFactory factory = new DaoFactory();
|
||||||
|
assertEquals(0, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
|
||||||
|
{
|
||||||
|
final Dao dao1 = factory.create();
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed1 = dao1.getClosed();
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed1.name());
|
||||||
|
closed1.close();
|
||||||
|
assertTrue(closed1.isClosed());
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed2 = dao1.getClosed();
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num2", closed2.name());
|
||||||
|
closed2.close();
|
||||||
|
assertTrue(closed2.isClosed());
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
|
||||||
|
dao1.close();
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
assertTrue(dao1.isClosed());
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
final Dao dao1 = factory.create();
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed1 = dao1.getClosed();
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed1.name());
|
||||||
|
|
||||||
|
final Closed closed2 = dao1.getClosed();
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num2", closed2.name());
|
||||||
|
|
||||||
|
assertEquals(5, dao1.getInt());
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
|
||||||
|
dao1.close();
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
assertTrue(dao1.isClosed());
|
||||||
|
assertFalse(closed1.isClosed());
|
||||||
|
assertFalse(closed2.isClosed());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingletonCloseable() throws Exception {
|
||||||
|
final DaoFactory factory = new DaoFactory();
|
||||||
|
assertEquals(0, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
final Dao dao1 = SingletonCloseable.of(Dao.class, factory);
|
||||||
|
|
||||||
|
{
|
||||||
|
assertEquals(0, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed1 = dao1.getClosed();
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed1.name());
|
||||||
|
closed1.close();
|
||||||
|
assertTrue(closed1.isClosed());
|
||||||
|
assertEquals(1, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed2 = dao1.getClosed();
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed2.name());
|
||||||
|
closed2.close();
|
||||||
|
assertTrue(closed2.isClosed());
|
||||||
|
assertEquals(2, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
|
||||||
|
dao1.close();
|
||||||
|
assertEquals(3, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
assertFalse(dao1.isClosed()); // always appears open even though does not stay open
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(4, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
|
||||||
|
final Closed closed1 = dao1.getClosed();
|
||||||
|
assertEquals(5, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed1.name());
|
||||||
|
|
||||||
|
final Closed closed2 = dao1.getClosed();
|
||||||
|
assertEquals(6, factory.totalOpened);
|
||||||
|
assertEquals(2, factory.numStillOpen);
|
||||||
|
assertEquals("num1", closed2.name());
|
||||||
|
|
||||||
|
assertEquals(5, dao1.getInt());
|
||||||
|
assertEquals(7, factory.totalOpened);
|
||||||
|
assertEquals(2, factory.numStillOpen);
|
||||||
|
|
||||||
|
dao1.close();
|
||||||
|
assertEquals(8, factory.totalOpened);
|
||||||
|
assertEquals(2, factory.numStillOpen);
|
||||||
|
assertFalse(dao1.isClosed());
|
||||||
|
assertEquals(9, factory.totalOpened);
|
||||||
|
assertEquals(2, factory.numStillOpen);
|
||||||
|
assertFalse(closed1.isClosed());
|
||||||
|
assertFalse(closed2.isClosed());
|
||||||
|
assertEquals(9, factory.totalOpened);
|
||||||
|
assertEquals(2, factory.numStillOpen);
|
||||||
|
closed1.close();
|
||||||
|
assertEquals(9, factory.totalOpened);
|
||||||
|
assertEquals(1, factory.numStillOpen);
|
||||||
|
closed2.close();
|
||||||
|
assertEquals(9, factory.totalOpened);
|
||||||
|
assertEquals(0, factory.numStillOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
class DaoFactory implements Factory<Dao> {
|
||||||
|
int totalOpened = 0;
|
||||||
|
int numStillOpen = 0;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dao create() throws SQLException {
|
||||||
|
return new DaoImpl(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DaoImpl implements Dao {
|
||||||
|
final DaoFactory factory;
|
||||||
|
|
||||||
|
private int simpleCloseableCount = 0;
|
||||||
|
private boolean closed = false;
|
||||||
|
|
||||||
|
DaoImpl(DaoFactory factory) {
|
||||||
|
++factory.totalOpened;
|
||||||
|
++factory.numStillOpen;
|
||||||
|
this.factory = factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() {
|
||||||
|
return closed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getInt() {
|
||||||
|
return 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Closed getClosed() {
|
||||||
|
return new SimpleCloseable("num" + (++simpleCloseableCount));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (!closed) {
|
||||||
|
--factory.numStillOpen;
|
||||||
|
closed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Dao extends Closeable {
|
||||||
|
boolean isClosed();
|
||||||
|
|
||||||
|
int getInt();
|
||||||
|
|
||||||
|
Closed getClosed();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package com.moparisthebest.jdbc;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class WrappingCloseableTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() throws IOException {
|
||||||
|
final Closed parent = new SimpleCloseable("parent");
|
||||||
|
final Closed child = new SimpleCloseable("child");
|
||||||
|
|
||||||
|
assertFalse(parent.isClosed());
|
||||||
|
assertEquals("parent", parent.name());
|
||||||
|
|
||||||
|
assertFalse(child.isClosed());
|
||||||
|
assertEquals("child", child.name());
|
||||||
|
|
||||||
|
final Closed wrapped = WrappingCloseable.wrap(child, Closed.class, parent);
|
||||||
|
// when wrapped is closed, it should close child and then parent
|
||||||
|
|
||||||
|
assertFalse(parent.isClosed());
|
||||||
|
assertEquals("parent", parent.name());
|
||||||
|
|
||||||
|
assertFalse(child.isClosed());
|
||||||
|
assertEquals("child", child.name());
|
||||||
|
|
||||||
|
assertFalse(wrapped.isClosed());
|
||||||
|
assertEquals("child", wrapped.name());
|
||||||
|
|
||||||
|
wrapped.close();
|
||||||
|
|
||||||
|
assertTrue(parent.isClosed());
|
||||||
|
assertEquals("parent", parent.name());
|
||||||
|
|
||||||
|
assertTrue(child.isClosed());
|
||||||
|
assertEquals("child", child.name());
|
||||||
|
|
||||||
|
assertTrue(wrapped.isClosed());
|
||||||
|
assertEquals("child", wrapped.name());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package com.moparisthebest.jdbc.codegen;
|
||||||
|
|
||||||
|
import com.moparisthebest.jdbc.Factory;
|
||||||
|
import com.moparisthebest.jdbc.QueryMapperTest;
|
||||||
|
import com.moparisthebest.jdbc.SingletonCloseable;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import static com.moparisthebest.jdbc.QueryMapperTest.fieldPerson1;
|
||||||
|
import static com.moparisthebest.jdbc.TryClose.tryClose;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class PersonDAOSingletonTest {
|
||||||
|
|
||||||
|
public static final PersonDAO personDAO = SingletonCloseable.of(PersonDAO.class, JdbcMapperFactory.of(PersonDAO.class, new Factory<Connection>() {
|
||||||
|
@Override
|
||||||
|
public Connection create() throws SQLException {
|
||||||
|
return QueryMapperTest.getConnection();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegularPersonDAO() throws Exception {
|
||||||
|
PersonDAO personDAO = null;
|
||||||
|
try {
|
||||||
|
personDAO = JdbcMapperFactory.create(PersonDAO.class, new Factory<Connection>() {
|
||||||
|
@Override
|
||||||
|
public Connection create() throws SQLException {
|
||||||
|
return QueryMapperTest.getConnection();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
testPerson(personDAO);
|
||||||
|
} finally {
|
||||||
|
tryClose(personDAO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSingletonPersonDAO() throws Exception {
|
||||||
|
testPerson(personDAO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testPerson(final PersonDAO personDAO) throws Exception {
|
||||||
|
assertEquals(fieldPerson1, personDAO.getPerson(fieldPerson1.getPersonNo()));
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
rs = personDAO.getPeopleResultSet(fieldPerson1.getLastName());
|
||||||
|
assertTrue(rs.next());
|
||||||
|
assertEquals(fieldPerson1.getLastName(), rs.getString("last_name"));
|
||||||
|
} finally {
|
||||||
|
tryClose(rs);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
rs = personDAO.getPeopleResultSetCached(fieldPerson1.getLastName());
|
||||||
|
assertTrue(rs.next());
|
||||||
|
assertEquals(fieldPerson1.getLastName(), rs.getString("last_name"));
|
||||||
|
} finally {
|
||||||
|
tryClose(rs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue