Fix breakage when encountering TYPE_USE annotations

This commit is contained in:
Travis Burtrum 2019-10-18 19:36:03 -04:00
parent 39dbefda64
commit 3a51d6ee56
17 changed files with 385 additions and 15 deletions

View File

@ -26,7 +26,7 @@ import java.util.stream.Stream;
//IFJAVA8_END
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.java8;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.typeMirrorStringNoGenerics;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.baseTypeMirrorString;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.typeMirrorToClass;
/**
@ -75,7 +75,7 @@ public class CompileTimeResultSetMapper {
// ignore?
}
}
return typeMirrorStringNoGenerics(returnType);
return baseTypeMirrorString(returnType.toString());
}
/**

View File

@ -14,6 +14,7 @@ import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.io.*;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
@ -1162,20 +1163,53 @@ public class JdbcMapperProcessor extends AbstractProcessor {
default:
return Class.forName("[L" + arrayComponentType.toString() + ";");
}
case DECLARED:
if (!((DeclaredType) tm).getTypeArguments().isEmpty()) {
return Class.forName(typeMirrorStringNoGenerics(tm));
}
// fallthrough otherwise...
default:
return Class.forName(tm.toString());
}
}
case DECLARED:
final DeclaredType dt = (DeclaredType) tm;
if (!dt.getTypeArguments().isEmpty()
//IFJAVA8_START
|| !dt.getAnnotationMirrors().isEmpty()
//IFJAVA8_END
) {
//messager.printMessage(Diagnostic.Kind.MANDATORY_WARNING, "dt.toString(): " + dt.toString() + " dt.getClass(): " + dt.getClass(), types.asElement(dt));
//return dt.getClass().getDeclaredMethod("unannotatedType").invoke(dt).toString(); // this is java 8 only
//return dt.getClass().getDeclaredMethod("getEnclosingType").invoke(dt); // modules prevent this 9+
public static String typeMirrorStringNoGenerics(final TypeMirror tm) {
final String classWithGenerics = tm.toString();
return classWithGenerics.substring(0, classWithGenerics.indexOf('<'));
}
return Class.forName(baseTypeMirrorString(tm.toString()));
}
// fallthrough otherwise...
default:
return Class.forName(tm.toString());
}
}
/**
* This is a terrible hack because I don't think a proper solution exists, the TypeUseAnnotation.java in the test module
* tests this functionality by being similar to real-world NotNull:
* <p>
* https://github.com/eclipse-ee4j/beanvalidation-api/blob/master/src/main/java/javax/validation/constraints/NotNull.java
* <p>
* The problem is they added TYPE_USE to the list of targets in this commit:
* <p>
* https://github.com/eclipse-ee4j/beanvalidation-api/commit/87ea7911ffc8578807ab78886e9483e87bcc7acd#diff-8aebda554210427d515ad1c7b1274d60
* <p>
* Which was well-known as a bad thing to do that cannot be handled all the way back in 2013 before Java 8 was even released:
* <p>
* https://mail.openjdk.java.net/pipermail/type-annotations-spec-comments/2013-October/000049.html
* <p>
* In practice, a type that used to be `java.lang.String` now reads as `(@javax.validation.constraints.NotNull :: java.lang.String)`
* with absolutely no documented way I can find to get the original type back out, the below way seems to work with
* the openjdk compilers 8-15 which was latest at the time of this writing, but I will continue to investigate a better
* way to do it.
*
* @param tm a DeclaredType that is an AnnotatedType underneath
* @return the DeclaredType as a String without generics or type annotations
*/
public static String baseTypeMirrorString(final String rawTypeString) {
return baseTypeBegin.matcher(baseTypeEnd.matcher(rawTypeString).replaceAll("")).replaceAll("");
}
private static final Pattern baseTypeEnd = Pattern.compile("(<.*|[)])$");
private static final Pattern baseTypeBegin = Pattern.compile("^.*\\s");
public ExecutableElement getCloseMethod(final TypeElement genClass) {
ExecutableElement ret = null;

View File

@ -0,0 +1,23 @@
package com.moparisthebest.jdbc.codegen;
import org.junit.Test;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.baseTypeMirrorString;
import static org.junit.Assert.*;
public class JdbcMapperProcessorTest {
@Test
public void baseTypeMirrorStringTest() {
// generics
assertEquals("java.util.List", baseTypeMirrorString("java.util.List<java.util.Map<java.lang.String,java.lang.String>>"));
assertEquals("java.util.Map", baseTypeMirrorString("java.util.Map<java.lang.String,java.lang.String>"));
assertEquals("java.util.Map", baseTypeMirrorString("java.util.Map<java.lang.String,java.util.List<com.moparisthebest.jdbc.dto.FieldPerson>>"));
// how java 8 formats TYPE_USE annotations
assertEquals("java.lang.String", baseTypeMirrorString("(@com.moparisthebest.jdbc.TypeUseAnnotation :: java.lang.String)"));
assertEquals("java.util.Date", baseTypeMirrorString("(@com.moparisthebest.jdbc.TypeUseAnnotation :: java.util.Date)"));
// how java 13 formats TYPE_USE annotations
assertEquals("java.lang.String", baseTypeMirrorString("@com.moparisthebest.jdbc.TypeUseAnnotation java.lang.String"));
assertEquals("java.util.Date", baseTypeMirrorString("@com.moparisthebest.jdbc.TypeUseAnnotation java.util.Date"));
}
}

View File

@ -0,0 +1,16 @@
package com.moparisthebest.jdbc;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER
//IFJAVA8_START
, TYPE_USE
//IFJAVA8_END
})
@Retention(RUNTIME)
public @interface TypeUseAnnotation {
}

View File

@ -85,6 +85,9 @@ public interface PersonDAO extends JdbcMapper {
@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 person_no, first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
TypeUsePerson getTypeUsePerson(long personNo, Calendar cal) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
List<FieldPerson> getPeople(String lastName) throws SQLException;

View File

@ -85,6 +85,9 @@ public interface PrestoPersonDAO extends PersonDAO {
@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 person_no, first_name, last_name, birth_date FROM person WHERE person_no = {personNo}")
TypeUsePerson getTypeUsePerson(long personNo, Calendar cal) throws SQLException;
@JdbcMapper.SQL("SELECT first_name, last_name FROM person WHERE last_name = {lastName}")
List<FieldPerson> getPeople(String lastName) throws SQLException;

View File

@ -0,0 +1,51 @@
package com.moparisthebest.jdbc.dto;
import com.moparisthebest.jdbc.TypeUseAnnotation;
import java.util.Date;
public class TypeUsePerson implements Person {
public long personNo;
@TypeUseAnnotation
public Date birthDate;
@TypeUseAnnotation
public String firstName, lastName;
public long getPersonNo() {
return personNo;
}
public Date getBirthDate() {
return birthDate;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
@Override
public boolean equals(final Object o) {
return PersonEqualsHashCode.equals(this, o);
}
@Override
public int hashCode() {
return PersonEqualsHashCode.hashCode(this);
}
@Override
public String toString() {
return this.getClass().getSimpleName()+"{" +
"personNo=" + personNo +
", birthDate=" + birthDate +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;

View File

@ -396,6 +396,30 @@ com.moparisthebest.jdbc.util.ReflectionUtil.setValue(_fields[2], ret, com.mopari
}
}
@Override
public com.moparisthebest.jdbc.dto.TypeUsePerson getTypeUsePerson(final long personNo, final java.util.Calendar cal) throws java.sql.SQLException {
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement("SELECT person_no, first_name, last_name, birth_date FROM person WHERE person_no = ?");
ps.setObject(1, personNo);
rs = ps.executeQuery();
if(rs.next()) {
final com.moparisthebest.jdbc.dto.TypeUsePerson ret = new com.moparisthebest.jdbc.dto.TypeUsePerson();
ret.personNo = rs.getLong(1);
ret.firstName = rs.getString(2);
ret.lastName = rs.getString(3);
ret.birthDate = com.moparisthebest.jdbc.util.ResultSetUtil.getUtilDate(rs, 4, cal);
return ret;
} else {
return null;
}
} finally {
tryClose(rs);
tryClose(ps);
}
}
@Override
public java.util.List<com.moparisthebest.jdbc.dto.FieldPerson> getPeople(final java.lang.String lastName) throws java.sql.SQLException {
PreparedStatement ps = null;