Implement Cleaner interface support in JdbcMapper, relax Cleaner interface

This commit is contained in:
Travis Burtrum 2017-06-07 21:29:28 -04:00
parent 85e0d868fe
commit d0d362c58c
4 changed files with 89 additions and 34 deletions

View File

@ -2,5 +2,5 @@ package com.moparisthebest.jdbc;
public interface Cleaner<T> { public interface Cleaner<T> {
public T clean(T dto); public <E extends T> E clean(E dto);
} }

View File

@ -56,17 +56,17 @@ public class CompileTimeResultSetMapper {
return typeMirrorStringNoGenerics(returnType); return typeMirrorStringNoGenerics(returnType);
} }
public void mapToResultType(final Writer w, final String[] keys, final ExecutableElement eeMethod, final int arrayMaxLength, final String cal) throws IOException, NoSuchMethodException, ClassNotFoundException { public void mapToResultType(final Writer w, final String[] keys, final ExecutableElement eeMethod, final int arrayMaxLength, final String cal, final String cleaner) throws IOException, NoSuchMethodException, ClassNotFoundException {
//final Method m = fromExecutableElement(eeMethod); //final Method m = fromExecutableElement(eeMethod);
//final Class returnType = m.getReturnType(); //final Class returnType = m.getReturnType();
final TypeMirror returnTypeMirror = eeMethod.getReturnType(); final TypeMirror returnTypeMirror = eeMethod.getReturnType();
//final Class returnType = typeMirrorToClass(returnTypeMirror); //final Class returnType = typeMirrorToClass(returnTypeMirror);
if (returnTypeMirror.getKind() == TypeKind.ARRAY) { if (returnTypeMirror.getKind() == TypeKind.ARRAY) {
final TypeMirror componentType = ((ArrayType) returnTypeMirror).getComponentType(); final TypeMirror componentType = ((ArrayType) returnTypeMirror).getComponentType();
toArray(w, keys, componentType, arrayMaxLength, cal); toArray(w, keys, componentType, arrayMaxLength, cal, cleaner);
} else if (types.isAssignable(returnTypeMirror, collectionType)) { } else if (types.isAssignable(returnTypeMirror, collectionType)) {
final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments(); final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments();
toCollection(w, keys, returnTypeMirror, typeArguments.get(0), arrayMaxLength, cal); toCollection(w, keys, returnTypeMirror, typeArguments.get(0), arrayMaxLength, cal, cleaner);
} else if (types.isAssignable(returnTypeMirror, mapType)) { } else if (types.isAssignable(returnTypeMirror, mapType)) {
final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments(); final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments();
//if (types[1] instanceof ParameterizedType) { // for collectionMaps //if (types[1] instanceof ParameterizedType) { // for collectionMaps
@ -78,18 +78,18 @@ public class CompileTimeResultSetMapper {
typeArguments.get(0), typeArguments.get(0),
collectionTypeMirror, collectionTypeMirror,
componentTypeMirror, componentTypeMirror,
arrayMaxLength, cal); arrayMaxLength, cal, cleaner);
return; return;
} }
toMap(w, keys, returnTypeMirror, typeArguments.get(0), typeArguments.get(1), arrayMaxLength, cal); toMap(w, keys, returnTypeMirror, typeArguments.get(0), typeArguments.get(1), arrayMaxLength, cal, cleaner);
} else if (types.isAssignable(returnTypeMirror, iteratorType)) { } else if (types.isAssignable(returnTypeMirror, iteratorType)) {
final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments(); final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments();
if (types.isAssignable(returnTypeMirror, listIteratorType)) if (types.isAssignable(returnTypeMirror, listIteratorType))
toListIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal); toListIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal, cleaner);
else else
toIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal); toIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal, cleaner);
} else { } else {
toObject(w, keys, returnTypeMirror, cal); toObject(w, keys, returnTypeMirror, cal, cleaner);
} }
} }
@ -101,13 +101,15 @@ public class CompileTimeResultSetMapper {
getRowMapper(keys, returnTypeMirror, cal, null, null).gen(w, returnTypeMirror.toString()); getRowMapper(keys, returnTypeMirror, cal, null, null).gen(w, returnTypeMirror.toString());
} }
public void toObject(final Writer w, final String[] keys, final TypeMirror returnTypeMirror, final String cal) throws IOException, ClassNotFoundException { public void toObject(final Writer w, final String[] keys, final TypeMirror returnTypeMirror, final String cal, final String cleaner) throws IOException, ClassNotFoundException {
w.write("\t\t\tif(rs.next()) {\n"); w.write("\t\t\tif(rs.next()) {\n");
writeObject(w, keys, returnTypeMirror, cal); writeObject(w, keys, returnTypeMirror, cal);
w.write("\t\t\t\treturn ret;\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n"); w.write("\t\t\t\treturn ");
// this does not clean null on purpose, neither does CleaningResultSetMapper
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, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void writeCollection(final Writer w, final String[] keys, final String returnTypeString, final String concreteTypeString, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
w.write("\t\t\tfinal "); w.write("\t\t\tfinal ");
w.write(returnTypeString); w.write(returnTypeString);
w.write(" _colret = new "); w.write(" _colret = new ");
@ -115,36 +117,37 @@ public class CompileTimeResultSetMapper {
w.write(returnTypeString.substring(returnTypeString.indexOf('<'))); w.write(returnTypeString.substring(returnTypeString.indexOf('<')));
w.write("();\n\t\t\twhile(rs.next()) {\n"); w.write("();\n\t\t\twhile(rs.next()) {\n");
writeObject(w, keys, componentTypeMirror, cal); writeObject(w, keys, componentTypeMirror, cal);
w.write("\t\t\t\t_colret.add(ret);\n\t\t\t}\n"); w.write("\t\t\t\t_colret.add(");
clean(w, cleaner).write(");\n\t\t\t}\n");
} }
public void toCollection(final Writer w, final String[] keys, final TypeMirror collectionTypeMirror, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void toCollection(final Writer w, final String[] keys, final TypeMirror collectionTypeMirror, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class); final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class);
writeCollection(w, keys, collectionTypeMirror.toString(), collectionType, componentTypeMirror, arrayMaxLength, cal); writeCollection(w, keys, collectionTypeMirror.toString(), collectionType, componentTypeMirror, arrayMaxLength, cal, cleaner);
w.write("\t\t\treturn _colret;\n"); w.write("\t\t\treturn _colret;\n");
} }
public void toArray(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void toArray(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String returnTypeString = componentTypeMirror.toString(); final String returnTypeString = componentTypeMirror.toString();
writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal, cleaner);
w.write("\t\t\treturn _colret.toArray(new "); w.write("\t\t\treturn _colret.toArray(new ");
w.write(returnTypeString); w.write(returnTypeString);
w.write("[_colret.size()]);\n"); w.write("[_colret.size()]);\n");
} }
public void toListIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void toListIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String returnTypeString = componentTypeMirror.toString(); final String returnTypeString = componentTypeMirror.toString();
writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal, cleaner);
w.write("\t\t\treturn _colret.listIterator();\n"); w.write("\t\t\treturn _colret.listIterator();\n");
} }
public void toIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void toIterator(final Writer w, final String[] keys, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String returnTypeString = componentTypeMirror.toString(); final String returnTypeString = componentTypeMirror.toString();
writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal); writeCollection(w, keys, "java.util.List<" + returnTypeString + ">", "java.util.ArrayList", componentTypeMirror, arrayMaxLength, cal, cleaner);
w.write("\t\t\treturn _colret.iterator();\n"); 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, int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { public void toMap(final Writer w, final String[] keys, final TypeMirror mapTypeMirror, final TypeMirror mapKeyTypeMirror, final TypeMirror componentTypeMirror, int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class); final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class);
final String returnTypeString = mapTypeMirror.toString(); final String returnTypeString = mapTypeMirror.toString();
w.write("\t\t\tfinal "); w.write("\t\t\tfinal ");
@ -159,16 +162,17 @@ public class CompileTimeResultSetMapper {
rm.gen(w, componentTypeMirror.toString()); rm.gen(w, componentTypeMirror.toString());
w.write("\t\t\t\t_colret.put("); w.write("\t\t\t\t_colret.put(");
rm.extractColumnValueString(w, 1, mapKeyTypeMirror); rm.extractColumnValueString(w, 1, mapKeyTypeMirror);
w.write(", ret);\n\t\t\t}\n"); w.write(", ");
clean(w, cleaner).write(");\n\t\t\t}\n");
w.write("\t\t\treturn _colret;\n"); w.write("\t\t\treturn _colret;\n");
} }
public void toMapCollection(final Writer w, final String[] keys, public void toMapCollection(final Writer w, final String[] keys,
final TypeMirror mapTypeMirror, final TypeMirror mapTypeMirror,
final TypeMirror mapKeyTypeMirror, final TypeMirror mapKeyTypeMirror,
final TypeMirror collectionTypeMirror, final TypeMirror collectionTypeMirror,
final TypeMirror componentTypeMirror, final TypeMirror componentTypeMirror,
int arrayMaxLength, String cal) throws IOException, ClassNotFoundException { int arrayMaxLength, String cal, final String cleaner) throws IOException, ClassNotFoundException {
final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class); final String mapType = getConcreteClassCanonicalName(mapTypeMirror, HashMap.class);
final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class); final String collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class);
final String returnTypeString = mapTypeMirror.toString(); final String returnTypeString = mapTypeMirror.toString();
@ -194,6 +198,16 @@ public class CompileTimeResultSetMapper {
w.write(" _collist = _colret.get(_colkey);\n\t\t\t\tif(_collist == null) {\n\t\t\t\t\t_collist = new "); w.write(" _collist = _colret.get(_colkey);\n\t\t\t\tif(_collist == null) {\n\t\t\t\t\t_collist = new ");
w.write(collectionType); w.write(collectionType);
w.write(collectionTypeString.substring(collectionTypeString.indexOf('<'))); w.write(collectionTypeString.substring(collectionTypeString.indexOf('<')));
w.write("();\n\t\t\t\t\t_colret.put(_colkey, _collist);\n\t\t\t\t}\n\t\t\t\t_collist.add(ret);\n\t\t\t}\n\t\t\treturn _colret;\n"); w.write("();\n\t\t\t\t\t_colret.put(_colkey, _collist);\n\t\t\t\t}\n\t\t\t\t_collist.add(");
clean(w, cleaner).write(");\n\t\t\t}\n\t\t\treturn _colret;\n");
}
private Writer clean(final Writer w, final String cleaner) throws IOException {
if(cleaner == null)
w.write("ret");
else {
w.append(cleaner).append(".clean(ret)");
}
return w;
} }
} }

View File

@ -1,5 +1,7 @@
package com.moparisthebest.jdbc.codegen; package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.Cleaner;
import javax.annotation.processing.*; import javax.annotation.processing.*;
import javax.lang.model.SourceVersion; import javax.lang.model.SourceVersion;
import javax.lang.model.element.*; import javax.lang.model.element.*;
@ -29,7 +31,8 @@ public class JdbcMapperProcessor extends AbstractProcessor {
private Types types; private Types types;
private TypeMirror sqlExceptionType, stringType, numberType, utilDateType, readerType, clobType, private TypeMirror sqlExceptionType, stringType, numberType, utilDateType, readerType, clobType,
byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, collectionType, calendarType; byteArrayType, inputStreamType, fileType, blobType, sqlArrayType, collectionType, calendarType, cleanerType;
private TypeElement cleanerElement;
private JdbcMapper.DatabaseType defaultDatabaseType; private JdbcMapper.DatabaseType defaultDatabaseType;
private String defaultArrayNumberTypeName, defaultArrayStringTypeName; private String defaultArrayNumberTypeName, defaultArrayStringTypeName;
private CompileTimeResultSetMapper rsm; private CompileTimeResultSetMapper rsm;
@ -60,6 +63,10 @@ public class JdbcMapperProcessor extends AbstractProcessor {
byteArrayType = types.getArrayType(types.getPrimitiveType(TypeKind.BYTE)); byteArrayType = types.getArrayType(types.getPrimitiveType(TypeKind.BYTE));
sqlArrayType = elements.getTypeElement(java.sql.Array.class.getCanonicalName()).asType(); sqlArrayType = elements.getTypeElement(java.sql.Array.class.getCanonicalName()).asType();
collectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getCanonicalName()), types.getWildcardType(null, null)); collectionType = types.getDeclaredType(elements.getTypeElement(Collection.class.getCanonicalName()), types.getWildcardType(null, null));
cleanerElement = elements.getTypeElement(Cleaner.class.getCanonicalName());
cleanerType = types.getDeclaredType(cleanerElement, types.getWildcardType(null, null));
final String databaseType = processingEnv.getOptions().get("JdbcMapper.databaseType"); final String databaseType = processingEnv.getOptions().get("JdbcMapper.databaseType");
defaultDatabaseType = databaseType == null ? JdbcMapper.DatabaseType.STANDARD : JdbcMapper.DatabaseType.valueOf(databaseType); defaultDatabaseType = databaseType == null ? JdbcMapper.DatabaseType.STANDARD : JdbcMapper.DatabaseType.valueOf(databaseType);
defaultArrayNumberTypeName = processingEnv.getOptions().get("JdbcMapper.arrayNumberTypeName"); defaultArrayNumberTypeName = processingEnv.getOptions().get("JdbcMapper.arrayNumberTypeName");
@ -212,7 +219,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
// build query and bind param order // build query and bind param order
final List<VariableElement> bindParams = new ArrayList<VariableElement>(); final List<VariableElement> bindParams = new ArrayList<VariableElement>();
final String sqlStatement; final String sqlStatement;
String calendarName = null; String calendarName = null, cleanerName = null;
boolean sqlExceptionThrown = false; boolean sqlExceptionThrown = false;
{ {
// now parameters // now parameters
@ -289,9 +296,22 @@ public class JdbcMapperProcessor extends AbstractProcessor {
for (final Map.Entry<String, VariableElement> unusedParam : unusedParams.entrySet()) { for (final Map.Entry<String, VariableElement> unusedParam : unusedParams.entrySet()) {
// look for lone calendar object // look for lone calendar object
if(types.isAssignable(unusedParam.getValue().asType(), calendarType) && calendarName == null) final TypeMirror unusedType = unusedParam.getValue().asType();
if(types.isAssignable(unusedType, calendarType) && calendarName == null)
calendarName = unusedParam.getKey(); calendarName = unusedParam.getKey();
else else if(types.isAssignable(unusedType, cleanerType) && cleanerName == null) {
cleanerName = unusedParam.getKey();
/*
// yuck this falls apart for anything other than plain objects, might as well just let it be a compile time error?
final TypeMirror requiredType = types.getDeclaredType(cleanerElement, types.getWildcardType(null, eeMethod.getReturnType()));
if(types.isAssignable(unusedType, requiredType))
cleanerName = unusedParam.getKey();
else
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR,
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
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format("@JdbcMapper.SQL method has unused parameter '%s'", unusedParam.getKey()), unusedParam.getValue()); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, String.format("@JdbcMapper.SQL method has unused parameter '%s'", unusedParam.getKey()), unusedParam.getValue());
} }
} }
@ -341,7 +361,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); processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, "@JdbcMapper.SQL sql parsed a wildcard column name which is not supported", methodElement);
return false; return false;
} }
rsm.mapToResultType(w, keys, eeMethod, sql.arrayMaxLength(), calendarName); rsm.mapToResultType(w, keys, eeMethod, sql.arrayMaxLength(), calendarName, cleanerName);
} }
// if no SQLException is thrown, we have to catch it here and wrap it with RuntimeException... // if no SQLException is thrown, we have to catch it here and wrap it with RuntimeException...

View File

@ -1,6 +1,8 @@
package com.moparisthebest.jdbc.codegen; package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.Cleaner;
import com.moparisthebest.jdbc.dto.FieldPerson; import com.moparisthebest.jdbc.dto.FieldPerson;
import com.moparisthebest.jdbc.dto.Person;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Time; import java.sql.Time;
@ -91,4 +93,23 @@ public interface PersonDAO {
java.util.Date getBirthDateUtilDate(long personNo) throws SQLException; java.util.Date getBirthDateUtilDate(long personNo) throws SQLException;
@JdbcMapper.SQL("SELECT birth_date FROM person WHERE person_no = {personNo}") @JdbcMapper.SQL("SELECT birth_date FROM person WHERE person_no = {personNo}")
java.util.Date getBirthDateUtilDate(long personNo, Calendar mycal) throws SQLException; java.util.Date getBirthDateUtilDate(long personNo, Calendar mycal) throws SQLException;
// cleaner checks
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
FieldPerson getPersonCleanFieldPerson(long personNo, Cleaner<FieldPerson> clean) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
FieldPerson getPersonCleanPerson(long personNo, Cleaner<Person> clean) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
FieldPerson getPersonCleanObject(long personNo, Cleaner<Object> clean) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
List<FieldPerson> getPersonCleanPersonList(long personNo, Cleaner<Person> clean) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
Map<String, FieldPerson> getPersonCleanPersonMap(long personNo, Cleaner<Person> clean) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
Map<String, List<FieldPerson>> getPersonCleanPersonMapList(long personNo, Cleaner<Person> clean) throws SQLException;
/*
// this should NOT compile:
@JdbcMapper.SQL("SELECT first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
FieldPerson getPersonCleanNumber(long personNo, Cleaner<Number> clean) throws SQLException;
*/
} }