Fix map and array mapping from CompilingResultSetMapper, add javadocs
This commit is contained in:
parent
61010ec39e
commit
34a7a55bfc
@ -7,6 +7,14 @@ import java.util.Calendar;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This generally follows the contract of ResultSetMapper, with the differences specified in CompilingRowToObjectMapper.
|
||||||
|
* <p>
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* @see CompilingRowToObjectMapper
|
||||||
|
*/
|
||||||
public class CompilingResultSetMapper extends ResultSetMapper {
|
public class CompilingResultSetMapper extends ResultSetMapper {
|
||||||
|
|
||||||
protected final Compiler compiler = new Compiler();
|
protected final Compiler compiler = new Compiler();
|
||||||
|
@ -12,7 +12,19 @@ import java.util.Calendar;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by mopar on 5/16/17.
|
* Map a ResultSet row to an Object. This mapper generates/compiles/executes java code to perform the mapping.
|
||||||
|
*
|
||||||
|
* @author Travis Burtrum (modifications from beehive)
|
||||||
|
* @author Travis Burtrum
|
||||||
|
* @see RowToObjectMapper for most details, will document here where this differs
|
||||||
|
* <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.
|
||||||
|
* <p>
|
||||||
|
* Subclass differences:
|
||||||
|
* 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<T> extends RowToObjectMapper<T> {
|
||||||
protected final Compiler compiler;
|
protected final Compiler compiler;
|
||||||
@ -72,12 +84,42 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected String typeFromName(final Class<?> type) {
|
protected String typeFromName(final Class<?> type) {
|
||||||
return type.getName(); // todo: naive for now
|
if (returnMap || componentType == null)
|
||||||
|
return type.getName();
|
||||||
|
else {
|
||||||
|
// an array, annoying syntax
|
||||||
|
final String name = type.getName();
|
||||||
|
final char charType = name.charAt(1);
|
||||||
|
switch (charType) {
|
||||||
|
case 'L':
|
||||||
|
return name.substring(2, name.length() - 1) + "[]";
|
||||||
|
case 'Z':
|
||||||
|
return "boolean[]";
|
||||||
|
case 'B':
|
||||||
|
return "byte[]";
|
||||||
|
case 'C':
|
||||||
|
return "char[]";
|
||||||
|
case 'D':
|
||||||
|
return "double[]";
|
||||||
|
case 'F':
|
||||||
|
return "float[]";
|
||||||
|
case 'I':
|
||||||
|
return "int[]";
|
||||||
|
case 'J':
|
||||||
|
return "long[]";
|
||||||
|
case 'S':
|
||||||
|
return "short[]";
|
||||||
|
case '[':
|
||||||
|
default:
|
||||||
|
throw new MapperException("only supports single dimensional array");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String escapeJavaString(final String s) {
|
protected String escapeMapKeyString(final String s) {
|
||||||
// todo: escape key string, newlines, double quotes, backslashes...
|
// todo: escape key string, newlines, double quotes, backslashes...
|
||||||
return s;
|
// actually it seems like those wouldn't be valid SQL column names, so we won't bother until we hear different...
|
||||||
|
return '"' + s + '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
// code generation down here
|
// code generation down here
|
||||||
@ -110,19 +152,19 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
|||||||
if (returnMap) // we want a map
|
if (returnMap) // we want a map
|
||||||
try {
|
try {
|
||||||
// todo: does not call getMapImplementation, I think that's fine
|
// todo: does not call getMapImplementation, I think that's fine
|
||||||
java.append("final Map<String, Object> ret = new ").append(tType).append("<String, Object>();\n");
|
java.append("final ").append(tType).append("<String, Object> ret = new ").append(tType).append("<String, Object>();\n");
|
||||||
final ResultSetMetaData md = _resultSet.getMetaData();
|
final ResultSetMetaData md = _resultSet.getMetaData();
|
||||||
final int columnLength = _columnCount + 1;
|
final int columnLength = _columnCount + 1;
|
||||||
if (componentType != null && componentType != Object.class) { // we want a specific value type
|
if (componentType != null && componentType != Object.class) { // we want a specific value type
|
||||||
int typeId = _tmf.getTypeId(componentType);
|
int typeId = _tmf.getTypeId(componentType);
|
||||||
for (int x = 1; x < columnLength; ++x) {
|
for (int x = 1; x < columnLength; ++x) {
|
||||||
java.append("ret.put(").append(escapeJavaString(md.getColumnName(x).toLowerCase())).append(", ");
|
java.append("ret.put(").append(escapeMapKeyString(md.getColumnName(x).toLowerCase())).append(", ");
|
||||||
extractColumnValueString(java, x, typeId);
|
extractColumnValueString(java, x, typeId);
|
||||||
java.append(");\n");
|
java.append(");\n");
|
||||||
}
|
}
|
||||||
} else // we want a generic object type
|
} else // we want a generic object type
|
||||||
for (int x = 1; x < columnLength; ++x)
|
for (int x = 1; x < columnLength; ++x)
|
||||||
java.append("ret.put(").append(escapeJavaString(md.getColumnName(x).toLowerCase())).append(", rs.getObject(").append(x).append("));\n");
|
java.append("ret.put(").append(escapeMapKeyString(md.getColumnName(x).toLowerCase())).append(", rs.getObject(").append(x).append("));\n");
|
||||||
java.append("return ret;\n");
|
java.append("return ret;\n");
|
||||||
return;
|
return;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
@ -132,8 +174,7 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
|||||||
}
|
}
|
||||||
else if (componentType != null) // we want an array
|
else if (componentType != null) // we want an array
|
||||||
try {
|
try {
|
||||||
// todo: array initialization syntax?
|
java.append("final ").append(tType).append(" ret = new ").append(tType.substring(0, tType.length() - 1)).append(_columnCount).append("];\n");
|
||||||
java.append("final ").append(tType).append("[] ret = new ").append(tType).append("[").append(_columnCount).append("];\n");
|
|
||||||
final int typeId = _tmf.getTypeId(componentType);
|
final int typeId = _tmf.getTypeId(componentType);
|
||||||
for (int x = 0; x < _columnCount; ) {
|
for (int x = 0; x < _columnCount; ) {
|
||||||
java.append("ret[").append(x).append("] = ");
|
java.append("ret[").append(x).append("] = ");
|
||||||
@ -141,6 +182,7 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
|||||||
java.append(";\n");
|
java.append(";\n");
|
||||||
}
|
}
|
||||||
java.append("return ret;\n");
|
java.append("return ret;\n");
|
||||||
|
return;
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
throw new MapperException(e.getClass().getName() + " when trying to create a "
|
throw new MapperException(e.getClass().getName() + " when trying to create a "
|
||||||
+ componentType.getName() + "[] from a ResultSet row, all columns must be of that type", e);
|
+ componentType.getName() + "[] from a ResultSet row, all columns must be of that type", e);
|
||||||
@ -236,7 +278,6 @@ public class CompilingRowToObjectMapper<T> extends RowToObjectMapper<T> {
|
|||||||
* @throws java.sql.SQLException on error.
|
* @throws java.sql.SQLException on error.
|
||||||
*/
|
*/
|
||||||
protected void extractColumnValueString(final StringBuilder java, final int index, final int resultType) {
|
protected void extractColumnValueString(final StringBuilder java, final int index, final int resultType) {
|
||||||
// todo: custom boolean
|
|
||||||
switch (resultType) {
|
switch (resultType) {
|
||||||
case TypeMappingsFactory.TYPE_INT:
|
case TypeMappingsFactory.TYPE_INT:
|
||||||
java.append("rs.getInt(").append(index).append(")");
|
java.append("rs.getInt(").append(index).append(")");
|
||||||
|
Loading…
Reference in New Issue
Block a user