diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java index 05af8c1..5e58086 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/CompilingRowToObjectMapper.java @@ -48,6 +48,7 @@ public class CompilingRowToObjectMapper extends RowToObjectMapper { this.keys = null; this._fields = null; this._fieldTypes = null; + this.constructor = null; } else { //System.out.printf("cache hit, keys: %s\n", keys); // load from cache @@ -144,6 +145,8 @@ public class CompilingRowToObjectMapper extends RowToObjectMapper { protected void gen(final StringBuilder java, final String tType) { + lazyLoadConstructor(); + if (resultSetConstructor) { java.append("return new ").append(tType).append("(rs);\n"); return; diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowMapper.java index a798111..f9dc5e3 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowMapper.java @@ -52,6 +52,8 @@ public abstract class RowMapper { /** Class to map ResultSet Rows to. */ protected final Class _returnTypeClass; + protected final int _columnCount; + /** * Create a new RowMapper for the specified ResultSet and return type Class. * @param resultSet ResultSet to map @@ -62,6 +64,12 @@ public abstract class RowMapper { _resultSet = resultSet; _returnTypeClass = returnTypeClass; _cal = cal; + + try { + _columnCount = resultSet.getMetaData().getColumnCount(); + } catch (SQLException e) { + throw new MapperException("RowToObjectMapper: SQLException: " + e.getMessage(), e); + } } /** @@ -80,10 +88,9 @@ public abstract class RowMapper { String[] keys; final ResultSetMetaData md = _resultSet.getMetaData(); - final int columnCount = md.getColumnCount(); - keys = new String[columnCount + 1]; - for (int i = 1; i <= columnCount; i++) { + keys = new String[_columnCount + 1]; + for (int i = 1; i <= _columnCount; i++) { keys[i] = md.getColumnName(i).toUpperCase(); } return keys; diff --git a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java index 74a2a46..1f6c3d6 100644 --- a/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java +++ b/beehive-jdbc-mapper/src/main/java/com/moparisthebest/jdbc/RowToObjectMapper.java @@ -52,16 +52,15 @@ public class RowToObjectMapper extends RowMapper { 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? - protected final int _columnCount; - protected final boolean resultSetConstructor; - protected final Constructor constructor; + protected boolean resultSetConstructor, constructorLoaded = false; + protected Constructor constructor; protected final Class _returnTypeClass; // over-ride non-generic version of this in super class // only non-null when _returnTypeClass is an array, or a map protected final Class componentType; protected final boolean returnMap; - protected AccessibleObject[] _fields; + protected AccessibleObject[] _fields = null; protected int[] _fieldTypes; protected final Object[] _args = new Object[1]; @@ -96,38 +95,35 @@ public class RowToObjectMapper extends RowMapper { // detect if we want an array back componentType = returnTypeClass.getComponentType(); } + } - _fields = null; - - try { - _columnCount = resultSet.getMetaData().getColumnCount(); - } catch (SQLException e) { - throw new MapperException("RowToObjectMapper: SQLException: " + e.getMessage(), e); - } - + protected void lazyLoadConstructor() { + if(constructorLoaded) + return; // detect if returnTypeClass has a constructor that takes a ResultSet, if so, our job couldn't be easier... boolean resultSetConstructor = false; - Constructor constructor = null; + Constructor constructor = null; try { - constructor = returnTypeClass.getConstructor(ResultSet.class); + constructor = _returnTypeClass.getConstructor(ResultSet.class); if (!constructor.isAccessible()) constructor.setAccessible(true); resultSetConstructor = true; } catch (Throwable e) { // if no resultSetConstructor find the constructor try { - constructor = returnTypeClass.getDeclaredConstructor(); + constructor = _returnTypeClass.getDeclaredConstructor(); if (!constructor.isAccessible()) constructor.setAccessible(true); } catch (Throwable e1) { // if column count is 2 or less, it might map directly to a type like a Long or something, or be a map which does // or if componentType is non-null, then we want an array like Long[] or String[] if(_columnCount > 2 && componentType == null) - throw new MapperException("Exception when trying to get constructor for : "+returnTypeClass.getName() + " Must have default no-arg constructor or one that takes a single ResultSet.", e1); + throw new MapperException("Exception when trying to get constructor for : "+_returnTypeClass.getName() + " Must have default no-arg constructor or one that takes a single ResultSet.", e1); } } this.resultSetConstructor = resultSetConstructor; this.constructor = constructor; + this.constructorLoaded = true; } /** @@ -148,6 +144,8 @@ public class RowToObjectMapper extends RowMapper { @SuppressWarnings({"unchecked"}) public T mapRowToReturnType() { + lazyLoadConstructor(); + if (resultSetConstructor) try { return constructor.newInstance(_resultSet);