mirror of
https://github.com/moparisthebest/JdbcMapper
synced 2025-02-09 19:50:11 -05:00
Allow CompilingRowToObjectMapper to use reflection for non-public fields optionally
This commit is contained in:
parent
f9ac10c70f
commit
115a62293e
@ -0,0 +1,26 @@
|
||||
package com.moparisthebest.jdbc.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Created by mopar on 6/19/17.
|
||||
*/
|
||||
public class ReflectionUtil {
|
||||
public static Field getAccessibleField(final Class<?> clazz, final String declaredField) {
|
||||
try {
|
||||
final Field ret = clazz.getDeclaredField(declaredField);
|
||||
ret.setAccessible(true);
|
||||
return ret;
|
||||
} catch (NoSuchFieldException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setValue(final Field field, final Object obj, final Object value) {
|
||||
try {
|
||||
field.set(obj, value);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import com.moparisthebest.jdbc.util.CacheUtil;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
@ -24,18 +26,7 @@ public class CachingResultSetMapper extends ResultSetMapper {
|
||||
*/
|
||||
public CachingResultSetMapper(final Calendar cal, final int arrayMaxLength, final int maxEntries) {
|
||||
super(cal, arrayMaxLength);
|
||||
if (maxEntries > 0) { // we want a limited cache
|
||||
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, CachingRowToObjectMapper.FieldMapping<?>>(initialCapacity, loadFactor, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(final Map.Entry<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>> eldest) {
|
||||
return size() > maxEntries;
|
||||
}
|
||||
};
|
||||
} else
|
||||
cache = new HashMap<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>>();
|
||||
cache = CacheUtil.getCache(maxEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -105,11 +96,7 @@ public class CachingResultSetMapper extends ResultSetMapper {
|
||||
* @param threadSafe true uses a thread-safe cache implementation (currently ConcurrentHashMap), false uses regular HashMap
|
||||
*/
|
||||
public CachingResultSetMapper(final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||
this(cal, arrayMaxLength, threadSafe ?
|
||||
new ConcurrentHashMap<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>>()
|
||||
:
|
||||
new HashMap<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>>()
|
||||
);
|
||||
this(cal, arrayMaxLength, CacheUtil.<CachingRowToObjectMapper.ResultSetKey, CachingRowToObjectMapper.FieldMapping<?>>getCache(threadSafe));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -11,52 +11,22 @@ public class CleaningCompilingResultSetMapper<E> extends CompilingResultSetMappe
|
||||
|
||||
private final Cleaner<E> cleaner;
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final int maxEntries) {
|
||||
super(cal, arrayMaxLength, maxEntries);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength) {
|
||||
super(cal, arrayMaxLength);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength) {
|
||||
super(arrayMaxLength);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner) {
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||
public CleaningCompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final CompilingRowToObjectMapper.Cache cache, final Cleaner<E> cleaner) {
|
||||
super(cal, arrayMaxLength, cache);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||
super(arrayMaxLength, cache);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?, ?>> cache) {
|
||||
public CleaningCompilingResultSetMapper(final CompilingRowToObjectMapper.Cache cache, final Cleaner<E> cleaner) {
|
||||
super(cache);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||
super(cal, arrayMaxLength, threadSafe);
|
||||
public CleaningCompilingResultSetMapper(final int arrayMaxLength, final CompilingRowToObjectMapper.Cache cache, final Cleaner<E> cleaner) {
|
||||
super(arrayMaxLength, cache);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final int arrayMaxLength, final boolean threadSafe) {
|
||||
super(arrayMaxLength, threadSafe);
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner, final boolean threadSafe) {
|
||||
super(threadSafe);
|
||||
public CleaningCompilingResultSetMapper(final Cleaner<E> cleaner) {
|
||||
this.cleaner = cleaner;
|
||||
}
|
||||
|
||||
|
@ -4,10 +4,6 @@ import com.moparisthebest.classgen.Compiler;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* This generally follows the contract of ResultSetMapper, with the differences specified in CompilingRowToObjectMapper.
|
||||
@ -15,132 +11,33 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* This does cache compiled code based on column name/order and DTO being mapped to, so the (rather heavy)
|
||||
* code generation/compilation/instantiation only happens once for each query/dto, and is very fast on subsequent calls.
|
||||
* <p>
|
||||
* By default this uses a plain HashMap for the cache, unbounded, and not thread-safe. There are overloaded constructors
|
||||
* you can use to tell it to be threadSafe in which case it uses an unbounded ConcurrentHashMap, or to give it a maxEntries
|
||||
* in which case it uses a LinkedHashMap and clears out old entries in LRU order keeping only maxEntries. Lastly you can
|
||||
* send in your own custom Map implementation, CompilingResultSetMapper guarantees null will never be used for key or value.
|
||||
* By default this uses a plain HashMap for the cache, unbounded, and not thread-safe. Use CacheUtil to get Maps for your
|
||||
* preferred use case. You cansend in your own custom Map implementation, CompilingResultSetMapper guarantees null will
|
||||
* never be used for key or value.
|
||||
*
|
||||
* @see CompilingRowToObjectMapper
|
||||
*/
|
||||
public class CompilingResultSetMapper extends ResultSetMapper {
|
||||
|
||||
protected final Compiler compiler = new Compiler();
|
||||
protected final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache;
|
||||
protected final CompilingRowToObjectMapper.Cache cache;
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with optional maxEntries, expiring old ones in LRU fashion
|
||||
*
|
||||
* @param cal optional calendar for date/time values
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
* @param maxEntries max cached compiled entries to keep in cache, < 1 means unlimited
|
||||
*/
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final int maxEntries) {
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final CompilingRowToObjectMapper.Cache cache) {
|
||||
super(cal, arrayMaxLength);
|
||||
if (maxEntries > 0) { // we want a limited cache
|
||||
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<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>(initialCapacity, loadFactor, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(final Map.Entry<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> eldest) {
|
||||
return size() > maxEntries;
|
||||
}
|
||||
};
|
||||
} else
|
||||
cache = new HashMap<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>();
|
||||
this.cache = cache == null ? new CompilingRowToObjectMapper.Cache() : cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with unlimited cache
|
||||
*
|
||||
* @param cal optional calendar for date/time values
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
*/
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength) {
|
||||
this(cal, arrayMaxLength, 0); // default unlimited cache
|
||||
public CompilingResultSetMapper(final CompilingRowToObjectMapper.Cache cache) {
|
||||
this.cache = cache == null ? new CompilingRowToObjectMapper.Cache() : cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with unlimited cache
|
||||
*
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
*/
|
||||
public CompilingResultSetMapper(final int arrayMaxLength) {
|
||||
this(null, arrayMaxLength);
|
||||
public CompilingResultSetMapper(final int arrayMaxLength, final CompilingRowToObjectMapper.Cache cache) {
|
||||
super(arrayMaxLength);
|
||||
this.cache = cache == null ? new CompilingRowToObjectMapper.Cache() : cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with unlimited cache
|
||||
*/
|
||||
public CompilingResultSetMapper() {
|
||||
this(-1);
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with custom cache implementation
|
||||
*
|
||||
* @param cal optional calendar for date/time values
|
||||
* @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<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
super(cal, arrayMaxLength);
|
||||
if (cache == null)
|
||||
throw new IllegalArgumentException("cache cannot be null");
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with custom cache implementation
|
||||
*
|
||||
* @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<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
this(null, arrayMaxLength, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with custom cache implementation
|
||||
*
|
||||
* @param cache any Map implementation for cache you wish, does not need to handle null keys or values
|
||||
*/
|
||||
public CompilingResultSetMapper(final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache) {
|
||||
this(-1, cache);
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with optionally threadSafe cache implementation
|
||||
*
|
||||
* @param cal optional calendar for date/time values
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
* @param threadSafe true uses a thread-safe cache implementation (currently ConcurrentHashMap), false uses regular HashMap
|
||||
*/
|
||||
public CompilingResultSetMapper(final Calendar cal, final int arrayMaxLength, final boolean threadSafe) {
|
||||
this(cal, arrayMaxLength, threadSafe ?
|
||||
new ConcurrentHashMap<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>()
|
||||
:
|
||||
new HashMap<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with optionally threadSafe cache implementation
|
||||
*
|
||||
* @param arrayMaxLength max array/list/map length, a value of less than 1 indicates that all rows from the ResultSet should be included
|
||||
* @param threadSafe true uses a thread-safe cache implementation (currently ConcurrentHashMap), false uses regular HashMap
|
||||
*/
|
||||
public CompilingResultSetMapper(final int arrayMaxLength, final boolean threadSafe) {
|
||||
this(null, arrayMaxLength, threadSafe);
|
||||
}
|
||||
|
||||
/**
|
||||
* CompilingResultSetMapper with optionally threadSafe cache implementation
|
||||
*
|
||||
* @param threadSafe true uses a thread-safe cache implementation (currently ConcurrentHashMap), false uses regular HashMap
|
||||
*/
|
||||
public CompilingResultSetMapper(final boolean threadSafe) {
|
||||
this(-1, threadSafe);
|
||||
this.cache = new CompilingRowToObjectMapper.Cache();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,15 +1,20 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import com.moparisthebest.classgen.Compiler;
|
||||
import com.sun.org.apache.xpath.internal.operations.Mod;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Calendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Map a ResultSet row to an Object. This mapper generates/compiles/executes java code to perform the mapping.
|
||||
@ -20,7 +25,8 @@ import java.util.Map;
|
||||
* <p>
|
||||
* Usage differences:
|
||||
* 1. Reflection can set non-public or final fields directly, direct java code cannot, so DTOs like that will result in
|
||||
* a compilation and therefore mapping error.
|
||||
* a compilation and therefore mapping error, unless the Cache sent in has allowReflection = true which will use reflection
|
||||
* for these Fields in the generated code.
|
||||
*/
|
||||
public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
@ -32,24 +38,28 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
protected String _calendarName = null;
|
||||
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CompilingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
protected int reflectionFieldIndex = -1;
|
||||
protected boolean allowReflection = false;
|
||||
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Cache cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType) {
|
||||
this(compiler, cache, resultSet, returnTypeClass, cal, mapValType, mapKeyType, false);
|
||||
}
|
||||
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Map<CompilingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType, final boolean caseInsensitiveMap) {
|
||||
public CompilingRowToObjectMapper(final Compiler compiler, final Cache cache, ResultSet resultSet, Class<T> returnTypeClass, Calendar cal, Class<?> mapValType, Class<K> mapKeyType, final boolean caseInsensitiveMap) {
|
||||
super(resultSet, returnTypeClass, cal, mapValType, mapKeyType, caseInsensitiveMap);
|
||||
this.compiler = compiler;
|
||||
try {
|
||||
final CompilingRowToObjectMapper.ResultSetKey keys = new CompilingRowToObjectMapper.ResultSetKey(super.getKeysFromResultSet(), _returnTypeClass, _mapKeyType, cal != null);
|
||||
//System.out.printf("keys: %s\n", keys);
|
||||
@SuppressWarnings("unchecked")
|
||||
final ResultSetToObject<K,T> resultSetToObject = (ResultSetToObject<K,T>) cache.get(keys);
|
||||
final ResultSetToObject<K,T> resultSetToObject = (ResultSetToObject<K,T>) cache.cache.get(keys);
|
||||
if (resultSetToObject == null) {
|
||||
//System.out.printf("cache miss, keys: %s\n", keys);
|
||||
// generate and put into cache
|
||||
if(keys.hasCalendar)
|
||||
_calendarName = "cal";
|
||||
cache.put(keys, this.resultSetToObject = genClass());
|
||||
allowReflection = cache.allowReflection;
|
||||
cache.cache.put(keys, this.resultSetToObject = genClass());
|
||||
this.keys = null;
|
||||
this._fields = null;
|
||||
this._fieldTypes = null;
|
||||
@ -109,6 +119,30 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
T toObject(final ResultSet rs, final Calendar cal) throws SQLException;
|
||||
}
|
||||
|
||||
public static class Cache {
|
||||
private final Map<CompilingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>> cache;
|
||||
private final boolean allowReflection;
|
||||
|
||||
public Cache(final Map<ResultSetKey, ResultSetToObject<?, ?>> cache, final boolean allowReflection) {
|
||||
if(cache == null)
|
||||
throw new NullPointerException("cache cannot be null");
|
||||
this.cache = cache;
|
||||
this.allowReflection = allowReflection;
|
||||
}
|
||||
|
||||
public Cache(final Map<ResultSetKey, ResultSetToObject<?, ?>> cache) {
|
||||
this(cache, false);
|
||||
}
|
||||
|
||||
public Cache() {
|
||||
this(new HashMap<CompilingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>>());
|
||||
}
|
||||
|
||||
public Cache(final boolean allowReflection) {
|
||||
this(new HashMap<CompilingRowToObjectMapper.ResultSetKey, ResultSetToObject<?,?>>(), allowReflection);
|
||||
}
|
||||
}
|
||||
|
||||
protected String typeFromName(final Class<?> type) {
|
||||
if(type == null)
|
||||
return "Object";
|
||||
@ -185,7 +219,21 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
java.append("throw new com.moparisthebest.jdbc.MapperException(com.moparisthebest.jdbc.CompilingRowToObjectMapper.firstColumnError)");
|
||||
}
|
||||
|
||||
java.append(footer);
|
||||
if(reflectionFieldIndex == -1) {
|
||||
java.append(footer);
|
||||
} else {
|
||||
// otherwise we have a reflection field array to set up...
|
||||
java.append(";\n }\n\n");
|
||||
java.append("private static final java.lang.reflect.Field[] _fields = new java.lang.reflect.Field[]{\n");
|
||||
for(final AccessibleObject ao : _fields)
|
||||
if(ao instanceof ReflectionAccessibleObject) {
|
||||
final Field f = ((ReflectionAccessibleObject)ao).field;
|
||||
java.append("com.moparisthebest.jdbc.util.ReflectionUtil.getAccessibleField(")
|
||||
.append(f.getDeclaringClass().getCanonicalName()).append(".class, \"")
|
||||
.append(f.getName()).append("\"),\n");
|
||||
}
|
||||
java.append("};\n}\n");
|
||||
}
|
||||
//System.out.println(java);
|
||||
return compiler.compile(className, java);
|
||||
}
|
||||
@ -287,19 +335,21 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
|
||||
for (int i = 1; i < _fields.length; i++) {
|
||||
AccessibleObject f = _fields[i];
|
||||
|
||||
String enumName = null;
|
||||
if (_fieldTypes[i] == TypeMappingsFactory.TYPE_ENUM) {
|
||||
enumName = (f instanceof Field ? ((Field) f).getType() : ((Method) f).getParameterTypes()[0]).getCanonicalName();
|
||||
}
|
||||
if (f instanceof Field) {
|
||||
// if f not accessible (but super.getFieldMappings() sets it), throw exception during compilation is fine
|
||||
java.append("ret.").append(((Field) f).getName()).append(" = ");
|
||||
extractColumnValueString(java, i, _fieldTypes[i], enumName);
|
||||
extractColumnValueString(java, i, _fieldTypes[i],
|
||||
_fieldTypes[i] == TypeMappingsFactory.TYPE_ENUM ? ((Field) f).getType().getCanonicalName() : null);
|
||||
java.append(";\n");
|
||||
} else if (f instanceof ReflectionAccessibleObject) {
|
||||
java.append("com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[").append(String.valueOf(((ReflectionAccessibleObject)f).index)).append("], ret, ");
|
||||
extractColumnValueString(java, i, _fieldTypes[i],
|
||||
_fieldTypes[i] == TypeMappingsFactory.TYPE_ENUM ? ((ReflectionAccessibleObject) f).field.getType().getCanonicalName() : null);
|
||||
java.append(");\n");
|
||||
} else {
|
||||
java.append("ret.").append(((Method) f).getName()).append("(");
|
||||
extractColumnValueString(java, i, _fieldTypes[i], enumName);
|
||||
extractColumnValueString(java, i, _fieldTypes[i],
|
||||
_fieldTypes[i] == TypeMappingsFactory.TYPE_ENUM ? ((Method) f).getParameterTypes()[0].getCanonicalName() : null);
|
||||
java.append(");\n");
|
||||
}
|
||||
}
|
||||
@ -308,6 +358,17 @@ public class CompilingRowToObjectMapper<K, T> extends RowToObjectMapper<K, T> {
|
||||
java.append("ret.finish(rs);\n");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessibleObject modField(final Field field, final int index) {
|
||||
if(!allowReflection)
|
||||
return field;
|
||||
final int modifiers = field.getModifiers();
|
||||
if(Modifier.isFinal(modifiers) || Modifier.isPrivate(modifiers) || Modifier.isProtected(modifiers)) {
|
||||
return new ReflectionAccessibleObject(field, ++reflectionFieldIndex);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
public void extractColumnValueString(final Appendable java, final int index, final int resultType, final String enumName) throws IOException {
|
||||
extractColumnValueString(java, index, resultType, enumName, _calendarName);
|
||||
}
|
||||
|
@ -0,0 +1,17 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import java.lang.reflect.AccessibleObject;
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* Created by mopar on 6/19/17.
|
||||
*/
|
||||
class ReflectionAccessibleObject extends AccessibleObject {
|
||||
final Field field;
|
||||
final int index;
|
||||
|
||||
public ReflectionAccessibleObject(final Field field, final int index) {
|
||||
this.field = field;
|
||||
this.index = index;
|
||||
}
|
||||
}
|
@ -452,16 +452,22 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
|
||||
+ "names and public setter methods on the return class. Columns are also "
|
||||
+ "stripped of '_' and compared if no match is found with them.");
|
||||
}
|
||||
f.setAccessible(true);
|
||||
_fields[i] = f;
|
||||
if (f instanceof Field) {
|
||||
_fieldTypes[i] = _tmf.getTypeId(((Field) f).getType());
|
||||
final Field field = (Field) f;
|
||||
_fields[i] = modField(field, i);
|
||||
_fieldTypes[i] = _tmf.getTypeId(field.getType());
|
||||
} else {
|
||||
_fieldTypes[i] = _tmf.getTypeId(((Method) f).getParameterTypes()[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected AccessibleObject modField(final Field field, final int index) {
|
||||
field.setAccessible(true);
|
||||
return field;
|
||||
}
|
||||
|
||||
public static <T> T fixNull(Class<T> returnType) {
|
||||
return returnType.cast(_tmf.fixNull(returnType));
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
package com.moparisthebest.jdbc;
|
||||
|
||||
import com.moparisthebest.jdbc.util.CacheUtil;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Global for entire application, hopefully you know what you are doing.
|
||||
*/
|
||||
public class StaticCompilingResultSetMapper extends CompilingResultSetMapper {
|
||||
|
||||
private static final Map<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>> cache = new ConcurrentHashMap<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>();
|
||||
private static final CompilingRowToObjectMapper.Cache cache = new CompilingRowToObjectMapper.Cache(CacheUtil.<CompilingRowToObjectMapper.ResultSetKey, CompilingRowToObjectMapper.ResultSetToObject<?,?>>getCache(true), true);
|
||||
|
||||
public static final StaticCompilingResultSetMapper instance = new StaticCompilingResultSetMapper();
|
||||
|
||||
|
@ -0,0 +1,35 @@
|
||||
package com.moparisthebest.jdbc.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by mopar on 6/19/17.
|
||||
*/
|
||||
public abstract class CacheUtil {
|
||||
|
||||
public static <K, V> Map<K, V> getCache(final int maxEntries) {
|
||||
if (maxEntries > 0) { // we want a limited cache
|
||||
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;
|
||||
return new LinkedHashMap<K, V>(initialCapacity, loadFactor, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(final Map.Entry<K, V> eldest) {
|
||||
return size() > maxEntries;
|
||||
}
|
||||
};
|
||||
} else
|
||||
return new HashMap<K, V>();
|
||||
}
|
||||
|
||||
public static <K, V> Map<K, V> getCache(final boolean threadSafe) {
|
||||
return threadSafe ?
|
||||
new ConcurrentHashMap<K, V>()
|
||||
:
|
||||
new HashMap<K, V>();
|
||||
}
|
||||
|
||||
}
|
@ -146,7 +146,7 @@ public class QueryMapperTest {
|
||||
{ new ResultSetMapper() },
|
||||
{ new CachingResultSetMapper() },
|
||||
{ new CaseInsensitiveMapResultSetMapper() },
|
||||
{ new CompilingResultSetMapper() },
|
||||
{ new CompilingResultSetMapper(new CompilingRowToObjectMapper.Cache(true)) },
|
||||
});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user