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 T clean(T dto);
public <E extends T> E clean(E dto);
}

View File

@ -56,17 +56,17 @@ public class CompileTimeResultSetMapper {
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 Class returnType = m.getReturnType();
final TypeMirror returnTypeMirror = eeMethod.getReturnType();
//final Class returnType = typeMirrorToClass(returnTypeMirror);
if (returnTypeMirror.getKind() == TypeKind.ARRAY) {
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)) {
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)) {
final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments();
//if (types[1] instanceof ParameterizedType) { // for collectionMaps
@ -78,18 +78,18 @@ public class CompileTimeResultSetMapper {
typeArguments.get(0),
collectionTypeMirror,
componentTypeMirror,
arrayMaxLength, cal);
arrayMaxLength, cal, cleaner);
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)) {
final List<? extends TypeMirror> typeArguments = ((DeclaredType) returnTypeMirror).getTypeArguments();
if (types.isAssignable(returnTypeMirror, listIteratorType))
toListIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal);
toListIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal, cleaner);
else
toIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal);
toIterator(w, keys, typeArguments.get(0), arrayMaxLength, cal, cleaner);
} 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());
}
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");
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(returnTypeString);
w.write(" _colret = new ");
@ -115,36 +117,37 @@ public class CompileTimeResultSetMapper {
w.write(returnTypeString.substring(returnTypeString.indexOf('<')));
w.write("();\n\t\t\twhile(rs.next()) {\n");
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);
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");
}
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();
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(returnTypeString);
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();
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");
}
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();
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");
}
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 returnTypeString = mapTypeMirror.toString();
w.write("\t\t\tfinal ");
@ -159,7 +162,8 @@ public class CompileTimeResultSetMapper {
rm.gen(w, componentTypeMirror.toString());
w.write("\t\t\t\t_colret.put(");
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");
}
@ -168,7 +172,7 @@ public class CompileTimeResultSetMapper {
final TypeMirror mapKeyTypeMirror,
final TypeMirror collectionTypeMirror,
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 collectionType = getConcreteClassCanonicalName(collectionTypeMirror, ArrayList.class);
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(collectionType);
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;
import com.moparisthebest.jdbc.Cleaner;
import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
@ -29,7 +31,8 @@ public class JdbcMapperProcessor extends AbstractProcessor {
private Types types;
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 String defaultArrayNumberTypeName, defaultArrayStringTypeName;
private CompileTimeResultSetMapper rsm;
@ -60,6 +63,10 @@ public class JdbcMapperProcessor extends AbstractProcessor {
byteArrayType = types.getArrayType(types.getPrimitiveType(TypeKind.BYTE));
sqlArrayType = elements.getTypeElement(java.sql.Array.class.getCanonicalName()).asType();
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");
defaultDatabaseType = databaseType == null ? JdbcMapper.DatabaseType.STANDARD : JdbcMapper.DatabaseType.valueOf(databaseType);
defaultArrayNumberTypeName = processingEnv.getOptions().get("JdbcMapper.arrayNumberTypeName");
@ -212,7 +219,7 @@ public class JdbcMapperProcessor extends AbstractProcessor {
// build query and bind param order
final List<VariableElement> bindParams = new ArrayList<VariableElement>();
final String sqlStatement;
String calendarName = null;
String calendarName = null, cleanerName = null;
boolean sqlExceptionThrown = false;
{
// now parameters
@ -289,9 +296,22 @@ public class JdbcMapperProcessor extends AbstractProcessor {
for (final Map.Entry<String, VariableElement> unusedParam : unusedParams.entrySet()) {
// 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();
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());
}
}
@ -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);
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...

View File

@ -1,6 +1,8 @@
package com.moparisthebest.jdbc.codegen;
import com.moparisthebest.jdbc.Cleaner;
import com.moparisthebest.jdbc.dto.FieldPerson;
import com.moparisthebest.jdbc.dto.Person;
import java.sql.SQLException;
import java.sql.Time;
@ -91,4 +93,23 @@ public interface PersonDAO {
java.util.Date getBirthDateUtilDate(long personNo) throws SQLException;
@JdbcMapper.SQL("SELECT birth_date FROM person WHERE person_no = {personNo}")
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;
*/
}