From d80a9325d75693cb5c8dbc1b337b8e64b25908e3 Mon Sep 17 00:00:00 2001 From: moparisthebest Date: Thu, 8 Jun 2017 01:27:56 -0400 Subject: [PATCH] Nicer dynamic type support for JdbcMapper maxRows, fixed unlimited loop on MAX_VALUE --- .../codegen/CompileTimeResultSetMapper.java | 69 +++++++++++++------ .../jdbc/codegen/JdbcMapperProcessor.java | 9 +-- .../jdbc/codegen/PersonDAO.java | 12 ++-- 3 files changed, 62 insertions(+), 28 deletions(-) diff --git a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/CompileTimeResultSetMapper.java b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/CompileTimeResultSetMapper.java index 9606659..d8484e9 100644 --- a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/CompileTimeResultSetMapper.java +++ b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/CompileTimeResultSetMapper.java @@ -56,7 +56,7 @@ public class CompileTimeResultSetMapper { return typeMirrorStringNoGenerics(returnType); } - public void mapToResultType(final Writer w, final String[] keys, final ExecutableElement eeMethod, final String maxRows, final String cal, final String cleaner) throws IOException, NoSuchMethodException, ClassNotFoundException { + public void mapToResultType(final Writer w, final String[] keys, final ExecutableElement eeMethod, final MaxRows maxRows, final String cal, final String cleaner) throws IOException, NoSuchMethodException, ClassNotFoundException { //final Method m = fromExecutableElement(eeMethod); //final Class returnType = m.getReturnType(); final TypeMirror returnTypeMirror = eeMethod.getReturnType(); @@ -109,7 +109,7 @@ public class CompileTimeResultSetMapper { clean(w, cleaner).write(";\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n"); } - public void writeCollection(final Writer w, final String[] keys, final String returnTypeString, final String concreteTypeString, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void writeCollection(final Writer w, final String[] keys, final String returnTypeString, final String concreteTypeString, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { maxRowInit(w, maxRows).write("\t\t\tfinal "); w.write(returnTypeString); w.write(" _colret = new "); @@ -122,13 +122,13 @@ public class CompileTimeResultSetMapper { maxRowBreak(w, maxRows).write("\t\t\t}\n"); } - public void toCollection(final Writer w, final String[] keys, final TypeMirror collectionTypeMirror, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void toCollection(final Writer w, final String[] keys, final TypeMirror collectionTypeMirror, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class); writeCollection(w, keys, collectionTypeMirror.toString(), collectionType, componentTypeMirror, maxRows, cal, cleaner); w.write("\t\t\treturn _colret;\n"); } - public void toArray(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void toArray(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String returnTypeString = componentTypeMirror.toString(); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, maxRows, cal, cleaner); w.write("\t\t\treturn _colret.toArray(new "); @@ -136,19 +136,19 @@ public class CompileTimeResultSetMapper { w.write("[_colret.size()]);\n"); } - public void toListIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void toListIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String returnTypeString = componentTypeMirror.toString(); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, maxRows, cal, cleaner); w.write("\t\t\treturn _colret.listIterator();\n"); } - public void toIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void toIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String returnTypeString = componentTypeMirror.toString(); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, maxRows, cal, cleaner); w.write("\t\t\treturn _colret.iterator();\n"); } - public void toMap(final Writer w, final String[] keys, final TypeMirror mapTypeMirror, final TypeMirror mapKeyTypeMirror, final TypeMirror componentTypeMirror, String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + public void toMap(final Writer w, final String[] keys, final TypeMirror mapTypeMirror, final TypeMirror mapKeyTypeMirror, final TypeMirror componentTypeMirror, MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class); final String returnTypeString = mapTypeMirror.toString(); maxRowInit(w, maxRows).write("\t\t\tfinal "); @@ -174,7 +174,7 @@ public class CompileTimeResultSetMapper { final TypeMirror mapKeyTypeMirror, final TypeMirror collectionTypeMirror, final TypeMirror componentTypeMirror, - String maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { + MaxRows maxRows, String cal, final String cleaner) throws IOException, ClassNotFoundException { final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class); final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class); final String returnTypeString = mapTypeMirror.toString(); @@ -206,24 +206,18 @@ public class CompileTimeResultSetMapper { maxRowBreak(w, maxRows).write("\t\t\t}\n\t\t\treturn _colret;\n"); } - private Writer maxRowInit(final Writer w, final String maxRows) throws IOException { + private Writer maxRowInit(final Writer w, final MaxRows maxRows) throws IOException { if(maxRows != null) - w.write("\t\t\tlong _rowCount = 1;\n"); // todo: use type of dynamic param, or minimum the hard coded number will fit in? + w.append("\t\t\t").append(maxRows.type).append(" _rowCount = 0;\n"); return w; } - private Writer maxRowBreak(final Writer w, final String maxRows) throws IOException { + private Writer maxRowBreak(final Writer w, final MaxRows maxRows) throws IOException { if(maxRows != null) { w.append("\t\t\t\tif("); - // annoying and hacky, but if this is a dynamic param name we want to only check rowCount if it's < 1 - // if it's a hard coded number, it'll be null so we won't even be here - try { - Long.parseLong(maxRows); - } catch (NumberFormatException e) { - // dynamic - w.append(maxRows).append(" > 0 && "); - } - w.append("++_rowCount > ").append(maxRows).append(")\n\t\t\t\t\tbreak;\n"); + if(maxRows.dynamic) + w.append(maxRows.value).append(" > 0 && "); + w.append("++_rowCount == ").append(maxRows.value).append(")\n\t\t\t\t\tbreak;\n"); } return w; } @@ -236,4 +230,39 @@ public class CompileTimeResultSetMapper { } return w; } + + static class MaxRows { + final String value, type; + final boolean dynamic; + + static MaxRows getMaxRows(final long value) { + return value < 1 ? null : new MaxRows(value); + } + + static MaxRows getMaxRows(final String value, final String type) { + return new MaxRows(value, type); + } + + private MaxRows(final long value) { + String valueString = Long.toString(value); + this.dynamic = false; + if(value <= Byte.MAX_VALUE) + this.type = "byte"; + else if(value <= Short.MAX_VALUE) + this.type = "short"; + else if(value <= Integer.MAX_VALUE) + this.type = "int"; + else { + this.type = "long"; + valueString += "L"; // fun! + } + this.value = valueString; + } + + private MaxRows(final String value, final String type) { + this.value = value; + this.type = type; + this.dynamic = true; + } + } } diff --git a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java index 89f891d..37f00af 100644 --- a/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java +++ b/jdbcmapper/src/main/java/com/moparisthebest/jdbc/codegen/JdbcMapperProcessor.java @@ -225,7 +225,8 @@ public class JdbcMapperProcessor extends AbstractProcessor { // build query and bind param order final List bindParams = new ArrayList(); final String sqlStatement; - String calendarName = null, cleanerName = null, maxRowsName = sql.maxRows() < 1 ? null : Long.toString(sql.maxRows()); + String calendarName = null, cleanerName = null; + CompileTimeResultSetMapper.MaxRows maxRows = CompileTimeResultSetMapper.MaxRows.getMaxRows(sql.maxRows()); boolean sqlExceptionThrown = false; { // now parameters @@ -317,8 +318,8 @@ public class JdbcMapperProcessor extends AbstractProcessor { String.format("@JdbcMapper.SQL method has unused parameter '%s' of cleaner type '%s' when cleaner type required is '%s'", unusedParam.getKey(), unusedType, requiredType), unusedParam.getValue()); */ - } else if(isPrimitiveInteger(unusedType.getKind()) && maxRowsName == null && this.allowedMaxRowParamNames.contains(unusedParam.getKey())) { - maxRowsName = unusedParam.getKey(); + } else if(isPrimitiveInteger(unusedType.getKind()) && maxRows == null && this.allowedMaxRowParamNames.contains(unusedParam.getKey())) { + maxRows = CompileTimeResultSetMapper.MaxRows.getMaxRows(unusedParam.getKey(), unusedType.toString()); } else processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format("@JdbcMapper.SQL method has unused parameter '%s'", unusedParam.getKey()), unusedParam.getValue()); } @@ -369,7 +370,7 @@ public class JdbcMapperProcessor extends AbstractProcessor { processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL sql parsed a wildcard column name which is not supported", methodElement); return false; } - rsm.mapToResultType(w, keys, eeMethod, maxRowsName, calendarName, cleanerName); + rsm.mapToResultType(w, keys, eeMethod, maxRows, calendarName, cleanerName); } // if no SQLException is thrown, we have to catch it here and wrap it with RuntimeException... diff --git a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java index ac9258b..32ca883 100644 --- a/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java +++ b/jdbcmapper/src/test/java/com/moparisthebest/jdbc/codegen/PersonDAO.java @@ -115,17 +115,21 @@ public interface PersonDAO { // max row checks @JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}") - List getPersonDynamicLimit(long personNo, int maxRows) throws SQLException; + Map getPersonDynamicLimit(long personNo, byte maxRows) throws SQLException; @JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}") Map getPersonDynamicLimit(long personNo, short arrayMaxLength) throws SQLException; @JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}") + List getPersonDynamicLimit(long personNo, int maxRows) throws SQLException; + @JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}") Map> getPersonDynamicLimit(long personNo, long rowLimit) throws SQLException; - @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = 1) + @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = Byte.MAX_VALUE) + List getPersonStaticLimitListByte(long personNo) throws SQLException; + @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = Short.MAX_VALUE) List getPersonStaticLimitList(long personNo) throws SQLException; - @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = 1) + @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = Integer.MAX_VALUE) Map getPersonStaticLimitMap(long personNo) throws SQLException; - @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = 1) + @JdbcMapper.SQL(value = "SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}", maxRows = Long.MAX_VALUE) Map> getPersonStaticLimitMapList(long personNo) throws SQLException; }