Somewhat major re-factor, all tests pass now
This commit is contained in:
parent
b425bb49b0
commit
e7639d740c
@ -132,7 +132,7 @@ public class CachingResultSetMapper extends ResultSetMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new CachingRowToObjectMapper<T>(cache, resultSet, returnTypeClass, cal, mapValType);
|
||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
return new CachingRowToObjectMapper<K, T>(cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
}
|
||||
|
@ -11,18 +11,18 @@ import java.util.Map;
|
||||
/**
|
||||
* Maps same as RowToObjectMapper except caches constructor and field mappings
|
||||
*/
|
||||
public class CachingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
public class CachingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
protected final Map<ResultSetKey, FieldMapping<T>> cache;
|
||||
protected final ResultSetKey keys;
|
||||
|
||||
public CachingRowToObjectMapper(final Map<ResultSetKey, FieldMapping<?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType);
|
||||
public CachingRowToObjectMapper(final Map<ResultSetKey, FieldMapping<?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
@SuppressWarnings("unchecked")
|
||||
final Map<ResultSetKey, FieldMapping<T>> genericCache = (Map<ResultSetKey, FieldMapping<T>>) (Object) cache; // ridiculous ain't it?
|
||||
this.cache = genericCache;
|
||||
try {
|
||||
keys = new ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass);
|
||||
keys = new ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass, _mapKeyType);
|
||||
//System.out.printf("keys: %s\n", keys);
|
||||
} catch (SQLException e) {
|
||||
throw new MapperException("CachingRowToObjectMapper: SQLException: " + e.getMessage(), e);
|
||||
@ -55,11 +55,12 @@ public class CachingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
|
||||
public static class ResultSetKey {
|
||||
protected final String[] keys;
|
||||
protected final Class<?> returnTypeClass;
|
||||
protected final Class<?> returnTypeClass, mapKeyType;
|
||||
|
||||
public ResultSetKey(final String[] keys, final Class<?> returnTypeClass) {
|
||||
public ResultSetKey(final String[] keys, final Class<?> returnTypeClass, final Class<?> mapKeyType) {
|
||||
this.keys = keys;
|
||||
this.returnTypeClass = returnTypeClass;
|
||||
this.mapKeyType = mapKeyType;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -69,13 +70,18 @@ public class CachingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
|
||||
final ResultSetKey that = (ResultSetKey) o;
|
||||
|
||||
return Arrays.equals(keys, that.keys) && (returnTypeClass != null ? returnTypeClass.equals(that.returnTypeClass) : that.returnTypeClass == null);
|
||||
// Probably incorrect - comparing Object[] arrays with Arrays.equals
|
||||
if (!Arrays.equals(keys, that.keys)) return false;
|
||||
if (returnTypeClass != null ? !returnTypeClass.equals(that.returnTypeClass) : that.returnTypeClass != null)
|
||||
return false;
|
||||
return mapKeyType != null ? mapKeyType.equals(that.mapKeyType) : that.mapKeyType == null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Arrays.hashCode(keys);
|
||||
result = 31 * result + (returnTypeClass != null ? returnTypeClass.hashCode() : 0);
|
||||
result = 31 * result + (mapKeyType != null ? mapKeyType.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -84,6 +90,7 @@ public class CachingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
return "ResultSetKey{" +
|
||||
"keys=" + Arrays.toString(keys) +
|
||||
", returnTypeClass=" + returnTypeClass +
|
||||
", mapKeyType=" + mapKeyType +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public class CaseInsensitiveMapResultSetMapper extends ResultSetMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new CaseInsensitiveMapRowToObjectMapper<T>(resultSet, returnTypeClass, cal, mapValType);
|
||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
return new CaseInsensitiveMapRowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import java.util.Map;
|
||||
/**
|
||||
* Created by mopar on 5/15/14.
|
||||
*/
|
||||
public class CaseInsensitiveMapRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
public class CaseInsensitiveMapRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass) {
|
||||
super(resultSet, returnTypeClass);
|
||||
}
|
||||
@ -25,6 +25,10 @@ public class CaseInsensitiveMapRowToObjectMapper<T> extends RowToObjectMapper<T>
|
||||
super(resultSet, returnTypeClass, cal, mapValType);
|
||||
}
|
||||
|
||||
public CaseInsensitiveMapRowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Map<String, Object> getMapImplementation() throws IllegalAccessException, InstantiationException {
|
||||
if(HashMap.class.equals(_returnTypeClass))
|
||||
|
@ -19,7 +19,7 @@ public class CleaningResultSetMapper<E> extends ResultSetMapper {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"unchecked"})
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new CleaningRowToObjectMapper<T>((Cleaner<T>)cleaner, resultSet, returnTypeClass, cal, mapValType);
|
||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
return new CleaningRowToObjectMapper<K, T>((Cleaner<T>)cleaner, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,22 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Calendar;
|
||||
|
||||
public class CleaningRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
public class CleaningRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
private final Cleaner<T> cleaner;
|
||||
|
||||
public CleaningRowToObjectMapper(Cleaner<T> cleaner, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType);
|
||||
public CleaningRowToObjectMapper(Cleaner<T> cleaner, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
if (cleaner == null)
|
||||
throw new NullPointerException("cleaner cannot be null!");
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T mapRowToReturnType() {
|
||||
public T mapRowToReturnType() throws SQLException {
|
||||
return cleaner.clean(super.mapRowToReturnType());
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
|
||||
protected final Compiler compiler = new Compiler();
|
||||
protected final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> cache;
|
||||
protected final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache;
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with optional maxEntries, expiring old ones in LRU fashion
|
||||
@ -40,14 +40,14 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
final float loadFactor = 0.75f; // default for HashMaps
|
||||
// if we set the initialCapacity this way, nothing should ever need re-sized
|
||||
final int initialCapacity = ((int) Math.ceil(maxEntries / loadFactor)) + 1;
|
||||
cache = new LinkedHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>>(initialCapacity, loadFactor, true) {
|
||||
cache = new LinkedHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>(initialCapacity, loadFactor, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(final Map.Entry<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> eldest) {
|
||||
protected boolean removeEldestEntry(final Map.Entry<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> eldest) {
|
||||
return size() > maxEntries;
|
||||
}
|
||||
};
|
||||
} else
|
||||
cache = new HashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>>();
|
||||
cache = new HashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,7 +83,7 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
* @param cache any Map implementation for cache you wish, does not need to handle null keys or values
|
||||
*/
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> cache) {
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
super(cal, arrayMaxLength);
|
||||
if (cache == null)
|
||||
throw new IllegalArgumentException("cache cannot be null");
|
||||
@ -96,7 +96,7 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
* @param cache any Map implementation for cache you wish, does not need to handle null keys or values
|
||||
*/
|
||||
public CompilingResultSetMapper(final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> cache) {
|
||||
public CompilingResultSetMapper(final int arrayMaxLength, final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
this(null, arrayMaxLength, cache);
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
*
|
||||
* @param cache any Map implementation for cache you wish, does not need to handle null keys or values
|
||||
*/
|
||||
public CompilingResultSetMapper(final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> cache) {
|
||||
public CompilingResultSetMapper(final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
this(-1, cache);
|
||||
}
|
||||
|
||||
@ -118,9 +118,9 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
*/
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||
this(cal, arrayMaxLength, threadSafe ?
|
||||
new ConcurrentHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>>()
|
||||
new ConcurrentHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>()
|
||||
:
|
||||
new HashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>>()
|
||||
new HashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>()
|
||||
);
|
||||
}
|
||||
|
||||
@ -144,7 +144,7 @@ public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new CompilingRowToObjectMapper<T>(compiler, cache, resultSet, returnTypeClass, cal, mapValType);
|
||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
return new CompilingRowToObjectMapper<K, T>(compiler, cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
}
|
||||
|
@ -26,20 +26,23 @@ import java.util.Map;
|
||||
* 1. Normally a subclass of RowToObjectMapper can overload the getMapImplementation() method to change some behavior,
|
||||
* @see CaseInsensitiveMapRowToObjectMapper , but that method is never called with this implementation.
|
||||
*/
|
||||
public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
public static final String firstColumnError = "Cannot call getFirstColumn when mapKeyType is null!";
|
||||
|
||||
protected final Compiler compiler;
|
||||
protected final ResultSetToObject<T> resultSetToObject;
|
||||
protected final ResultSetToObject<K, T> resultSetToObject;
|
||||
|
||||
protected String[] keys = null; // for caching if we must generate class
|
||||
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CachingRowToObjectMapper.ResultSetKey, ResultSetToObject<?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType);
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CachingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
this.compiler = compiler;
|
||||
try {
|
||||
final CachingRowToObjectMapper.ResultSetKey keys = new CachingRowToObjectMapper.ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass);
|
||||
final CachingRowToObjectMapper.ResultSetKey keys = new CachingRowToObjectMapper.ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass, _mapKeyType);
|
||||
//System.out.printf("keys: %s\n", keys);
|
||||
@SuppressWarnings("unchecked")
|
||||
final ResultSetToObject<T> resultSetToObject = (ResultSetToObject<T>) cache.get(keys);
|
||||
final ResultSetToObject<K,T> resultSetToObject = (ResultSetToObject<K,T>) cache.get(keys);
|
||||
if (resultSetToObject == null) {
|
||||
//System.out.printf("cache miss, keys: %s\n", keys);
|
||||
// generate and put into cache
|
||||
@ -60,15 +63,15 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T mapRowToReturnType() {
|
||||
try {
|
||||
return resultSetToObject.toObject(_resultSet, _cal);
|
||||
} catch (SQLException e) {
|
||||
throw new MapperException(e.getMessage(), e);
|
||||
}
|
||||
public T mapRowToReturnType() throws SQLException {
|
||||
return resultSetToObject.toObject(_resultSet, _cal);
|
||||
}
|
||||
|
||||
// todo: generate/cache these to make it faster for Map and MapCollection? maybe just getKey and getVal methods instead
|
||||
@Override
|
||||
public K getMapKey() throws SQLException {
|
||||
return resultSetToObject.getFirstColumn(_resultSet, _cal);
|
||||
}
|
||||
// todo: generate/cache these to make it faster for Map and MapCollection? maybe just getKey and getVal methods instead
|
||||
/*
|
||||
@Override
|
||||
public <E> E extractColumnValue(final int index, final Class<E> classType) throws SQLException {
|
||||
@ -88,11 +91,14 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
throw new MapperException("not supported here");
|
||||
}
|
||||
|
||||
public interface ResultSetToObject<T> {
|
||||
public interface ResultSetToObject<K, T> {
|
||||
K getFirstColumn(final ResultSet rs, final Calendar cal) throws SQLException;
|
||||
T toObject(final ResultSet rs, final Calendar cal) throws SQLException;
|
||||
}
|
||||
|
||||
protected String typeFromName(final Class<?> type) {
|
||||
if(type == null)
|
||||
return "Object";
|
||||
if(_columnCount == 1 && type.isPrimitive()) {
|
||||
// need the object equivalent here, what is the best way? this works, isn't pretty...
|
||||
if(type.equals(Character.TYPE))
|
||||
@ -141,27 +147,44 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
||||
}
|
||||
|
||||
// code generation down here
|
||||
protected ResultSetToObject<T> genClass() {
|
||||
protected ResultSetToObject<K, T> genClass() {
|
||||
final String className = "CompilingMapper";
|
||||
final String tType = typeFromName(_returnTypeClass);
|
||||
final String kType = typeFromName(_mapKeyType);
|
||||
final String header =
|
||||
"import static com.moparisthebest.jdbc.util.ResultSetUtil.*;\n\n" +
|
||||
"public final class " + className +
|
||||
" implements com.moparisthebest.jdbc.CompilingRowToObjectMapper.ResultSetToObject<" + tType + "> {\n" +
|
||||
" implements com.moparisthebest.jdbc.CompilingRowToObjectMapper.ResultSetToObject<"+ kType +"," + tType + "> {\n" +
|
||||
" public " + tType + " toObject(final java.sql.ResultSet rs, final java.util.Calendar cal) throws java.sql.SQLException {\n";
|
||||
final String footer = " }\n" +
|
||||
final String footer = ";\n }\n" +
|
||||
"}\n";
|
||||
|
||||
final StringBuilder java = new StringBuilder(header);
|
||||
//java.append("return null;\n");
|
||||
gen(java, tType);
|
||||
|
||||
java.append(" }\n\n public ").append(kType).append(" getFirstColumn(final java.sql.ResultSet rs, final java.util.Calendar cal) throws java.sql.SQLException {\n ");
|
||||
if(_mapKeyType != null){
|
||||
java.append("return ");
|
||||
extractColumnValueString(java, 1, _tmf.getTypeId(_mapKeyType));
|
||||
} else {
|
||||
java.append("throw new com.moparisthebest.jdbc.MapperException(com.moparisthebest.jdbc.CompilingRowToObjectMapper.firstColumnError)");
|
||||
}
|
||||
|
||||
java.append(footer);
|
||||
//System.out.println(java);
|
||||
System.out.println(java);
|
||||
return compiler.compile(className, java);
|
||||
}
|
||||
|
||||
protected void gen(final StringBuilder java, final String tType) {
|
||||
|
||||
if(mapOnlySecondColumn){
|
||||
java.append("return ");
|
||||
extractColumnValueString(java, 2, _tmf.getTypeId(_returnTypeClass));
|
||||
java.append(";\n");
|
||||
return;
|
||||
}
|
||||
|
||||
lazyLoadConstructor();
|
||||
|
||||
if (resultSetConstructor) {
|
||||
|
@ -120,7 +120,7 @@ public class ResultSetMapper {
|
||||
T ret = null;
|
||||
try {
|
||||
if (rs.next())
|
||||
ret = getRowMapper(rs, componentType, cal, mapValType).mapRowToReturnType();
|
||||
ret = getRowMapper(rs, componentType, cal, mapValType, null).mapRowToReturnType();
|
||||
} catch (SQLException e) {
|
||||
// ignore
|
||||
}
|
||||
@ -151,7 +151,7 @@ public class ResultSetMapper {
|
||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||
|
||||
final RowToObjectMapper<E> rowMapper = getRowMapper(rs, componentType, cal, mapValType);
|
||||
final RowToObjectMapper<?, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, null);
|
||||
|
||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||
E object = rowMapper.mapRowToReturnType();
|
||||
@ -230,12 +230,11 @@ public class ResultSetMapper {
|
||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||
|
||||
final RowToObjectMapper<E> rowMapper = getRowMapper(rs, componentType, cal, mapValType);
|
||||
final RowToObjectMapper<K, E> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
||||
|
||||
boolean onlyTwoColumns = rowMapper.getColumnCount() == 2;
|
||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||
K key = rowMapper.extractColumnValue(1, mapKeyType);
|
||||
E value = onlyTwoColumns ? rowMapper.extractColumnValue(2, componentType) : rowMapper.mapRowToReturnType();
|
||||
K key = rowMapper.getMapKey();
|
||||
E value = rowMapper.mapRowToReturnType();
|
||||
|
||||
map = softMap.get();
|
||||
if (map == null)
|
||||
@ -312,12 +311,11 @@ public class ResultSetMapper {
|
||||
// a value of less than 1 indicates that all rows from the ResultSet should be included.
|
||||
final boolean unlimitedRows = arrayMaxLength < 1;
|
||||
|
||||
final RowToObjectMapper<C> rowMapper = getRowMapper(rs, componentType, cal, mapValType);
|
||||
final RowToObjectMapper<K, C> rowMapper = getRowMapper(rs, componentType, cal, mapValType, mapKeyType);
|
||||
|
||||
boolean onlyTwoColumns = rowMapper.getColumnCount() == 2;
|
||||
for (; (unlimitedRows || numRows != arrayMaxLength) && rs.next(); ++numRows) {
|
||||
K key = rowMapper.extractColumnValue(1, mapKeyType);
|
||||
C value = onlyTwoColumns ? rowMapper.extractColumnValue(2, componentType) : rowMapper.mapRowToReturnType();
|
||||
K key = rowMapper.getMapKey();
|
||||
C value = rowMapper.mapRowToReturnType();
|
||||
|
||||
map = softMap.get();
|
||||
if (map == null)
|
||||
@ -406,8 +404,8 @@ public class ResultSetMapper {
|
||||
}
|
||||
|
||||
// fairly un-interesting methods below here
|
||||
protected <T> RowToObjectMapper<T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
return new RowToObjectMapper<T>(resultSet, returnTypeClass, cal, mapValType);
|
||||
protected <K, T> RowToObjectMapper<K, T> getRowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
return new RowToObjectMapper<K, T>(resultSet, returnTypeClass, cal, mapValType, mapKeyType);
|
||||
}
|
||||
|
||||
protected void warnOnMaxLength(final int numRows, final int arrayMaxLength, final ResultSet rs) {
|
||||
|
@ -37,7 +37,7 @@ import java.util.regex.Pattern;
|
||||
* RowMapperFactory.
|
||||
*
|
||||
*/
|
||||
public abstract class RowMapper {
|
||||
public abstract class RowMapper<K, T> {
|
||||
|
||||
private static final String SETTER_NAME_REGEX = "^(set)([A-Z_]\\w*+)";
|
||||
protected static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance();
|
||||
@ -50,34 +50,51 @@ public abstract class RowMapper {
|
||||
protected final Calendar _cal;
|
||||
|
||||
/** Class to map ResultSet Rows to. */
|
||||
protected final Class<?> _returnTypeClass;
|
||||
protected final Class<T> _returnTypeClass;
|
||||
|
||||
protected final Class<K> _mapKeyType;
|
||||
|
||||
protected final int _columnCount;
|
||||
|
||||
protected final boolean mapOnlySecondColumn;
|
||||
|
||||
/**
|
||||
* Create a new RowMapper for the specified ResultSet and return type Class.
|
||||
* @param resultSet ResultSet to map
|
||||
* @param returnTypeClass Class to map ResultSet rows to.
|
||||
* @param cal Calendar instance for date/time values.
|
||||
*/
|
||||
protected RowMapper(ResultSet resultSet, Class<?> returnTypeClass, Calendar cal) {
|
||||
protected RowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<K> mapKeyType) {
|
||||
_resultSet = resultSet;
|
||||
_returnTypeClass = returnTypeClass;
|
||||
_cal = cal;
|
||||
_mapKeyType = mapKeyType;
|
||||
|
||||
try {
|
||||
_columnCount = resultSet.getMetaData().getColumnCount();
|
||||
} catch (SQLException e) {
|
||||
throw new MapperException("RowToObjectMapper: SQLException: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
mapOnlySecondColumn = _mapKeyType != null && _columnCount == 2;
|
||||
}
|
||||
|
||||
protected RowMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal) {
|
||||
this(resultSet, returnTypeClass, cal, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Map a ResultSet row to the return type class
|
||||
* @return An instance of class.
|
||||
* @return An instance of class, if _mapKeyType is not null and _columnCount is 2, return only index 2
|
||||
*/
|
||||
public abstract Object mapRowToReturnType();
|
||||
public abstract T mapRowToReturnType() throws SQLException;
|
||||
|
||||
/**
|
||||
* key for map
|
||||
* @return index number 1, with type of _mapKeyType
|
||||
* @throws MapperException if _mapKeyType is null
|
||||
*/
|
||||
public abstract K getMapKey() throws SQLException;
|
||||
|
||||
/**
|
||||
* Build a String array of column names from the ResultSet.
|
||||
|
@ -47,7 +47,7 @@ import static com.moparisthebest.jdbc.UpdateableDTO.NO;
|
||||
*
|
||||
* @author Travis Burtrum (modifications from beehive)
|
||||
*/
|
||||
public class RowToObjectMapper<T> extends RowMapper {
|
||||
public class RowToObjectMapper<K, T> extends RowMapper<K, T> {
|
||||
|
||||
public static final int TYPE_BOOLEAN = _tmf.getTypeId(Boolean.TYPE);//TypeMappingsFactory.TYPE_BOOLEAN; // not public?
|
||||
public static final int TYPE_BOOLEAN_OBJ = _tmf.getTypeId(Boolean.class);//TypeMappingsFactory.TYPE_BOOLEAN_OBJ; // not public?
|
||||
@ -77,6 +77,11 @@ public class RowToObjectMapper<T> extends RowMapper {
|
||||
this(resultSet, returnTypeClass, cal, null);
|
||||
}
|
||||
|
||||
|
||||
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
this(resultSet, returnTypeClass, cal, mapValType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new RowToObjectMapper.
|
||||
*
|
||||
@ -84,8 +89,8 @@ public class RowToObjectMapper<T> extends RowMapper {
|
||||
* @param returnTypeClass Class to map to.
|
||||
* @param cal Calendar instance for date/time mappings.
|
||||
*/
|
||||
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType) {
|
||||
super(resultSet, returnTypeClass, cal);
|
||||
public RowToObjectMapper(ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
super(resultSet, returnTypeClass, cal, mapKeyType);
|
||||
returnMap = Map.class.isAssignableFrom(returnTypeClass);
|
||||
if(returnMap){
|
||||
_returnTypeClass = ResultSetMapper.getConcreteClass(returnTypeClass, HashMap.class);
|
||||
@ -136,13 +141,21 @@ public class RowToObjectMapper<T> extends RowMapper {
|
||||
return (Map<String, Object>)_returnTypeClass.newInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public K getMapKey() throws SQLException {
|
||||
return this.extractColumnValue(1, _mapKeyType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Do the mapping.
|
||||
*
|
||||
* @return An object instance.
|
||||
*/
|
||||
@SuppressWarnings({"unchecked"})
|
||||
public T mapRowToReturnType() {
|
||||
public T mapRowToReturnType() throws SQLException {
|
||||
|
||||
if(mapOnlySecondColumn)
|
||||
return this.extractColumnValue(2, _returnTypeClass);
|
||||
|
||||
lazyLoadConstructor();
|
||||
|
||||
@ -300,15 +313,6 @@ public class RowToObjectMapper<T> extends RowMapper {
|
||||
return classType.cast(extractColumnValue(index, _tmf.getTypeId(classType)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provided so we know whether to map all values to a type, or just the second one
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public int getColumnCount() {
|
||||
return this._columnCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the structures necessary to do the mapping
|
||||
*
|
||||
|
@ -9,7 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class StaticCompilingResultSetMapper extends CompilingResultSetMapper {
|
||||
|
||||
private static final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>> cache = new ConcurrentHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?>>();
|
||||
private static final Map<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache = new ConcurrentHashMap<CachingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>();
|
||||
|
||||
public static final StaticCompilingResultSetMapper instance = new StaticCompilingResultSetMapper();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user