Call super(Connection) if it exists, tweak cannot find Constructor error message

This commit is contained in:
Travis Burtrum 2018-03-17 00:42:22 -04:00
parent 50ebcc84cb
commit f68fd749e3
4 changed files with 57 additions and 10 deletions

View File

@ -2,6 +2,7 @@ package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.CompilingRowToObjectMapper; import com.moparisthebest.jdbc.CompilingRowToObjectMapper;
import com.moparisthebest.jdbc.MapperException; import com.moparisthebest.jdbc.MapperException;
import com.moparisthebest.jdbc.RowToObjectMapper;
import com.moparisthebest.jdbc.TypeMappingsFactory; import com.moparisthebest.jdbc.TypeMappingsFactory;
import javax.lang.model.element.*; import javax.lang.model.element.*;
@ -95,7 +96,7 @@ public class CompileTimeRowToObjectMapper {
*/ */
outer: outer:
for(final Element e : methodsAndConstructors) { for(final Element e : methodsAndConstructors) {
if(e.getKind() == ElementKind.CONSTRUCTOR && e.getModifiers().contains(Modifier.PUBLIC)) { if(e.getKind() == ElementKind.CONSTRUCTOR && e.getModifiers().contains(Modifier.PUBLIC)) { // todo: public normally, but also package-private if same package, or protected if it's a sub-class of super...
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;
@ -134,7 +135,8 @@ public class CompileTimeRowToObjectMapper {
_fieldOrder = null; // didn't successfully finish _fieldOrder = null; // didn't successfully finish
this.resultSetConstructor = resultSetConstructor; this.resultSetConstructor = resultSetConstructor;
if(!resultSetConstructor && !defaultConstructor && !paramConstructor && _columnCount > 2 && componentType == null) if(!resultSetConstructor && !defaultConstructor && !paramConstructor && _columnCount > 2 && componentType == null)
throw new MapperException("Exception when trying to get constructor for : "+_returnTypeClass.toString() + " Must have default no-arg constructor or one that takes a single ResultSet."); throw new MapperException("Exception when trying to get constructor for : "+_returnTypeClass.toString() + " Must have default no-arg constructor, one that takes a single ResultSet, or one that takes parameters named like the query columns (in any order):\n" +
RowToObjectMapper.keysToString(keys)+ "\nRequires compilation with -parameters argument if source isn't being compiled this pass, beware Bug ID: JDK-8191074 with jdk8, fixed in 9+");
} }
} }

View File

@ -15,6 +15,7 @@ import javax.tools.Diagnostic;
import java.io.*; import java.io.*;
import java.sql.Blob; import java.sql.Blob;
import java.sql.Clob; import java.sql.Clob;
import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.regex.Matcher; import java.util.regex.Matcher;
@ -65,7 +66,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
return messager; return messager;
} }
static TypeMirror sqlExceptionType, stringType, numberType, utilDateType, readerType, clobType, jdbcMapperType, static TypeMirror sqlExceptionType, stringType, numberType, utilDateType, readerType, clobType, connectionType, jdbcMapperType,
byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, collectionType, calendarType, cleanerType, enumType; byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, collectionType, calendarType, cleanerType, enumType;
//IFJAVA8_START //IFJAVA8_START
static TypeMirror instantType, localDateTimeType, localDateType, localTimeType, zonedDateTimeType, offsetDateTimeType, offsetTimeType; static TypeMirror instantType, localDateTimeType, localDateType, localTimeType, zonedDateTimeType, offsetDateTimeType, offsetTimeType;
@ -97,6 +98,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
utilDateType = elements.getTypeElement(java.util.Date.class.getCanonicalName()).asType(); utilDateType = elements.getTypeElement(java.util.Date.class.getCanonicalName()).asType();
readerType = elements.getTypeElement(Reader.class.getCanonicalName()).asType(); readerType = elements.getTypeElement(Reader.class.getCanonicalName()).asType();
clobType = elements.getTypeElement(Clob.class.getCanonicalName()).asType(); clobType = elements.getTypeElement(Clob.class.getCanonicalName()).asType();
connectionType = elements.getTypeElement(Connection.class.getCanonicalName()).asType();
jdbcMapperType = elements.getTypeElement(JdbcMapper.class.getCanonicalName()).asType(); jdbcMapperType = elements.getTypeElement(JdbcMapper.class.getCanonicalName()).asType();
inputStreamType = elements.getTypeElement(InputStream.class.getCanonicalName()).asType(); inputStreamType = elements.getTypeElement(InputStream.class.getCanonicalName()).asType();
fileType = elements.getTypeElement(File.class.getCanonicalName()).asType(); fileType = elements.getTypeElement(File.class.getCanonicalName()).asType();
@ -234,10 +236,19 @@ public class JdbcMapperProcessor extends AbstractProcessor {
w.write(className); w.write(className);
w.write("() throws SQLException {\n\t\tthis(_conFactory);\n\t}\n"); w.write("() throws SQLException {\n\t\tthis(_conFactory);\n\t}\n");
} }
w.write("\n\tprivate ");
w.write(className);
w.write("(final Connection conn, final boolean closeConn) {\n");
if(hasSuperConstructorTakesConnection(genClass))
w.write("\t\tsuper(conn);\n");
w.write("\t\tthis.conn = conn;\n\t\tthis.closeConn = closeConn;\n\t\tif (this.conn == null)\n" +
"\t\t\tthrow new NullPointerException(\"Connection needs to be non-null for JdbcMapper...\");\n\t}\n"
);
w.write("\n\tpublic "); w.write("\n\tpublic ");
w.write(className); w.write(className);
w.write("(Connection conn) {\n\t\tthis.conn = conn;\n\t\tthis.closeConn = false;\n\t\tif (this.conn == null)\n" + w.write("(Connection conn) {\n\t\tthis(conn, false);\n\t}\n" +
"\t\t\tthrow new NullPointerException(\"Connection needs to be non-null for JdbcMapper...\");\n\t}\n" +
"\n\tpublic Connection getConnection() {\n\t\treturn this.conn;\n\t}\n" "\n\tpublic Connection getConnection() {\n\t\treturn this.conn;\n\t}\n"
); );
@ -541,8 +552,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
// and we can create constructors that set closeConn to true! // and we can create constructors that set closeConn to true!
w.write("\n\tpublic "); w.write("\n\tpublic ");
w.write(className); w.write(className);
w.write("(final Factory<Connection> connectionFactory) throws SQLException {\n\t\tthis.conn = connectionFactory.create();\n\t\tthis.closeConn = true;\n\t\tif (this.conn == null)\n" + w.write("(final Factory<Connection> connectionFactory) throws SQLException {\n\t\tthis(connectionFactory.create(), true);\n\t}\n"
"\t\t\tthrow new NullPointerException(\"Connection needs to be non-null for JdbcMapper...\");\n\t}\n"
); );
w.write("\n\tpublic "); w.write("\n\tpublic ");
@ -950,4 +960,16 @@ public class JdbcMapperProcessor extends AbstractProcessor {
tryClose(pw); tryClose(pw);
} }
} }
public boolean hasSuperConstructorTakesConnection(final TypeElement genClass) {
final List<? extends Element> methodsAndConstructors = genClass.getEnclosedElements();
for(final Element e : methodsAndConstructors) {
if (e.getKind() == ElementKind.CONSTRUCTOR && !e.getModifiers().contains(Modifier.PRIVATE)) {
final List<? extends VariableElement> params = ((ExecutableElement)e).getParameters();
if(params.size() == 1 && types.isSameType(params.get(0).asType(), connectionType))
return true;
}
}
return false;
}
} }

View File

@ -197,7 +197,11 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
// 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"
//IFJAVA8_START
+ ", or one that takes parameters named like the query columns (in any order):\n" + keysToString(keys) + "\nRequires compilation with -parameters argument, beware Bug ID: JDK-8191074 with jdk8, fixed in 9+"
//IFJAVA8_END
, e1);
} }
} }
} }
@ -208,6 +212,24 @@ public class RowToObjectMapper<K, T> extends AbstractRowMapper<K, T> {
this.constructorLoaded = true; this.constructorLoaded = true;
} }
public static String keysToString(final String[] a) {
if (a == null)
return "null";
int iMax = a.length - 1;
if (iMax == 0)
return "[]";
StringBuilder b = new StringBuilder();
b.append('[');
for (int i = 1; ; i++) {
b.append(String.valueOf(a[i]));
if (i == iMax)
return b.append(']').toString();
b.append(", ");
}
}
/** /**
* This returns a new instance of the Map class required by Map<String, Object>[] * This returns a new instance of the Map class required by Map<String, Object>[]
* It lives in it's own method to minimize suppressed warnings and allow subclasses to override methods, * It lives in it's own method to minimize suppressed warnings and allow subclasses to override methods,

View File

@ -118,5 +118,6 @@ try(QueryMapper qm = new QueryMapper("java:/comp/env/jdbc/testPool", new ResultS
TODO TODO
---- ----
* Binding of Enum to String by default * DOCUMENTATION!!!!!
* sql other than select return boolean, int > 0 ? * sql other than select return boolean, int > 0 ?
* @RunInTransaction void support