Add constructor calling for jdbcmapper and discover bug in javac 1.8 with -parameters option
This commit is contained in:
parent
d2df6dabaf
commit
df2ccda9fa
|
@ -49,7 +49,8 @@ public class CompileTimeRowToObjectMapper {
|
||||||
protected final boolean returnMap, resultSetConstructor;
|
protected final boolean returnMap, resultSetConstructor;
|
||||||
|
|
||||||
protected Element[] _fields = null;
|
protected Element[] _fields = null;
|
||||||
protected int[] _fieldTypes;
|
protected int[] _fieldTypes, _fieldOrder;
|
||||||
|
protected String[] _fieldClasses;
|
||||||
|
|
||||||
protected final ReflectionFields reflectionFields;
|
protected final ReflectionFields reflectionFields;
|
||||||
|
|
||||||
|
@ -78,21 +79,62 @@ public class CompileTimeRowToObjectMapper {
|
||||||
componentType = returnTypeClass.getKind() == TypeKind.ARRAY ? ((ArrayType) returnTypeClass).getComponentType() : null;
|
componentType = returnTypeClass.getKind() == TypeKind.ARRAY ? ((ArrayType) returnTypeClass).getComponentType() : null;
|
||||||
|
|
||||||
// detect if returnTypeClass has a constructor that takes a ResultSet, if so, our job couldn't be easier...
|
// detect if returnTypeClass has a constructor that takes a ResultSet, if so, our job couldn't be easier...
|
||||||
boolean resultSetConstructor = false, defaultConstructor = false;
|
boolean resultSetConstructor = false, defaultConstructor = false, paramConstructor = false;
|
||||||
if(_returnTypeClass.getKind() == TypeKind.DECLARED) {
|
if(_returnTypeClass.getKind() == TypeKind.DECLARED) {
|
||||||
|
Map<String, Integer> strippedKeys = null;
|
||||||
final List<? extends Element> methodsAndConstructors = ((TypeElement)((DeclaredType)_returnTypeClass).asElement()).getEnclosedElements();
|
final List<? extends Element> methodsAndConstructors = ((TypeElement)((DeclaredType)_returnTypeClass).asElement()).getEnclosedElements();
|
||||||
|
|
||||||
|
/*
|
||||||
|
// uncomment this to show difference between java 1.8 with -parameters and not, prints this without -parameters (javac 1.6 gets this correct also):
|
||||||
|
// methodsAndConstructors: FieldPerson(): '', FieldPerson(long,java.util.Date,java.lang.String,java.lang.String): 'long PERSONNO, java.util.Date BIRTHDATE, java.lang.String FIRSTNAME, java.lang.String LASTNAME', FieldPerson(com.moparisthebest.jdbc.dto.Person): 'com.moparisthebest.jdbc.dto.Person PERSON'
|
||||||
|
// but javac 1.8 prints this with -parameters (wrongly):
|
||||||
|
// methodsAndConstructors: FieldPerson(): '', FieldPerson(long,java.util.Date,java.lang.String,java.lang.String): 'long PERSONNO, java.util.Date FIRSTNAME, java.lang.String LASTNAME, java.lang.String ARG3', FieldPerson(com.moparisthebest.jdbc.dto.Person): 'com.moparisthebest.jdbc.dto.Person PERSON'
|
||||||
|
if(_returnTypeClass.toString().equals("com.moparisthebest.jdbc.dto.FieldPerson"))
|
||||||
|
throw new RuntimeException("methodsAndConstructors: " + methodsAndConstructors.stream().filter(e -> e.getKind() == ElementKind.CONSTRUCTOR && e.getModifiers().contains(Modifier.PUBLIC)).map(e -> e.toString() +
|
||||||
|
": '" + ((ExecutableElement)e).getParameters().stream().map(param -> param.asType() + " " + param.getSimpleName().toString().toUpperCase()).collect(java.util.stream.Collectors.joining(", ")) + "'"
|
||||||
|
).collect(java.util.stream.Collectors.joining(", ")));
|
||||||
|
*/
|
||||||
|
outer:
|
||||||
for(final Element e : methodsAndConstructors) {
|
for(final Element e : methodsAndConstructors) {
|
||||||
if(e.getKind() == ElementKind.CONSTRUCTOR) {
|
if(e.getKind() == ElementKind.CONSTRUCTOR && e.getModifiers().contains(Modifier.PUBLIC)) {
|
||||||
final List<? extends VariableElement> params = ((ExecutableElement)e).getParameters();
|
final List<? extends VariableElement> params = ((ExecutableElement)e).getParameters();
|
||||||
if(params.isEmpty())
|
if(params.isEmpty())
|
||||||
defaultConstructor = true;
|
defaultConstructor = true;
|
||||||
else if(params.size() == 1 && rsm.types.isSameType(params.get(0).asType(), rsm.resultSetType))
|
else if(params.size() == 1 && rsm.types.isSameType(params.get(0).asType(), rsm.resultSetType))
|
||||||
resultSetConstructor = true;
|
resultSetConstructor = true;
|
||||||
|
else if(params.size() == _columnCount) {
|
||||||
|
// maybe we want to call the constructor, if the names line up
|
||||||
|
if(strippedKeys == null) {
|
||||||
|
strippedKeys = new HashMap<String, Integer>(keys.length * 2);
|
||||||
|
for (int x = 1; x <= _columnCount; ++x) {
|
||||||
|
final String key = keys[x];
|
||||||
|
strippedKeys.put(key, x);
|
||||||
|
strippedKeys.put(key.replaceAll("_", ""), x);
|
||||||
|
}
|
||||||
|
_fieldOrder = new int[keys.length];
|
||||||
|
_fieldTypes = new int[keys.length];
|
||||||
|
_fieldClasses = new String[keys.length];
|
||||||
|
}
|
||||||
|
int count = 0;
|
||||||
|
for(final VariableElement param : params) {
|
||||||
|
final Integer index = strippedKeys.get(param.getSimpleName().toString().toUpperCase());
|
||||||
|
if(index == null)
|
||||||
|
continue outer;
|
||||||
|
_fieldOrder[++count] = index;
|
||||||
|
_fieldTypes[count] = getTypeId(param.asType());
|
||||||
|
if(_fieldTypes[count] == TypeMappingsFactory.TYPE_ENUM) {
|
||||||
|
_fieldClasses[count] = param.asType().toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
paramConstructor = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(!paramConstructor)
|
||||||
|
_fieldOrder = null; // didn't successfully finish
|
||||||
this.resultSetConstructor = resultSetConstructor;
|
this.resultSetConstructor = resultSetConstructor;
|
||||||
if(!resultSetConstructor && !defaultConstructor && _columnCount > 2 && componentType == null)
|
if(!resultSetConstructor && !defaultConstructor && !paramConstructor && _columnCount > 2 && componentType == null)
|
||||||
throw new RuntimeException("Exception when trying to get constructor for : "+_returnTypeClass.toString() + " Must have default no-arg constructor or one that takes a single ResultSet.");
|
throw new RuntimeException("Exception when trying to get constructor for : "+_returnTypeClass.toString() + " Must have default no-arg constructor or one that takes a single ResultSet.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,6 +312,17 @@ public class CompileTimeRowToObjectMapper {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(_fieldOrder != null) {
|
||||||
|
java.append("final ").append(tType).append(" ret = new ").append(tType).append("(\n");
|
||||||
|
for(int x = 1; x <= _columnCount; ++x) {
|
||||||
|
extractColumnValueString(java, _fieldOrder[x], _fieldTypes[x], _fieldClasses[x]);
|
||||||
|
if(x != _columnCount)
|
||||||
|
java.append(",\n");
|
||||||
|
}
|
||||||
|
java.append(");\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (returnMap) // we want a map
|
if (returnMap) // we want a map
|
||||||
try {
|
try {
|
||||||
java.append("final ").append(tType).append("<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");
|
||||||
|
|
|
@ -44,12 +44,12 @@ public interface PersonDAO extends Closeable {
|
||||||
@JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo}")
|
@JdbcMapper.SQL("SELECT first_name FROM person WHERE person_no = {personNo}")
|
||||||
String getFirstName(long personNo) throws SQLException;
|
String getFirstName(long personNo) throws SQLException;
|
||||||
|
|
||||||
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
|
|
||||||
FieldPerson getPerson(long personNo, Calendar cal) throws SQLException;
|
|
||||||
|
|
||||||
@JdbcMapper.SQL(value = "SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
|
@JdbcMapper.SQL(value = "SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
|
||||||
FieldPerson getPerson(long personNo) throws SQLException;
|
FieldPerson getPerson(long personNo) throws SQLException;
|
||||||
|
|
||||||
|
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
|
||||||
|
FieldPerson getPerson(long personNo, Calendar cal) throws SQLException;
|
||||||
|
|
||||||
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
|
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
|
||||||
List<FieldPerson> getPeople(String lastName) throws SQLException;
|
List<FieldPerson> getPeople(String lastName) throws SQLException;
|
||||||
|
|
||||||
|
|
|
@ -191,7 +191,8 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//IFJAVA8_END
|
//IFJAVA8_END
|
||||||
if(constructor == null)
|
if(constructor == null) {
|
||||||
|
_fieldOrder = null; // we didn't complete this...
|
||||||
try {
|
try {
|
||||||
constructor = _returnTypeClass.getDeclaredConstructor();
|
constructor = _returnTypeClass.getDeclaredConstructor();
|
||||||
if (!constructor.isAccessible())
|
if (!constructor.isAccessible())
|
||||||
|
@ -199,9 +200,10 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
|
||||||
} catch (Throwable e1) {
|
} 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
|
// 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[]
|
// or if componentType is non-null, then we want an array like Long[] or String[]
|
||||||
if(_columnCount > 2 && componentType == null)
|
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.resultSetConstructor = resultSetConstructor;
|
||||||
this.constructor = constructor;
|
this.constructor = constructor;
|
||||||
|
|
Loading…
Reference in New Issue