@ -1,15 +1,20 @@
@@ -1,15 +1,20 @@
package com.moparisthebest.jdbc.codegen ;
import javax.lang.model.element.* ;
import javax.lang.model.type.DeclaredType ;
import javax.lang.model.type.TypeKind ;
import javax.lang.model.type.TypeMirror ;
import java.lang.annotation.Annotation ;
import java.util.List ;
import java.util.Set ;
import javax.tools.Diagnostic ;
import java.util.* ;
import static com.moparisthebest.jdbc.codegen.CompileTimeRowToObjectMapper.getAllImplementedTypes ;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.booleanType ;
import static com.moparisthebest.jdbc.codegen.JdbcMapperProcessor.types ;
/ * *
* Created by mopar on 6 / 1 / 17 .
* /
class SpecialVariableElement implements VariableElement {
class SpecialVariableElement extends Delegating VariableElement {
enum SpecialType {
BIND_IN_LIST ,
@ -18,36 +23,172 @@ class SpecialVariableElement implements VariableElement {
@@ -18,36 +23,172 @@ class SpecialVariableElement implements VariableElement {
BLOB ,
SQL ,
STR_BOOLEAN ,
PLAIN ,
}
final VariableElement delegate ;
final SpecialType specialType ;
final String blobStringCharset ;
final int index ;
final boolean iterable , bindable ;
final boolean iterable , bindable , allowReflection ;
TypeMirror type ;
String name , componentTypeString ;
SpecialVariableElement ( final VariableElement delegate , final SpecialType specialType ) {
this ( delegate , specialType , null , 0 ) ;
SpecialVariableElement ( final boolean allowReflection , final VariableElement delegate , final String paramName , final int indexOfFirstPeriod , final SpecialType specialType ) {
this ( allowReflection , delegate , paramName , indexOfFirstPeriod , specialType , null , 0 ) ;
}
SpecialVariableElement ( final VariableElement delegate , final SpecialType specialType , final int index ) {
this ( delegate , specialType , null , index ) ;
SpecialVariableElement ( final boolean allowReflection , final VariableElement delegate , final String paramName , final int indexOfFirstPeriod , final SpecialType specialType , final int index ) {
this ( allowReflection , delegate , paramName , indexOfFirstPeriod , specialType , null , index ) ;
}
SpecialVariableElement ( final VariableElement delegate , final SpecialType specialType , final String blobStringCharset ) {
this ( delegate , specialType , blobStringCharset , 0 ) ;
SpecialVariableElement ( final boolean allowReflection , final VariableElement delegate , final String paramName , final int indexOfFirstPeriod , final SpecialType specialType , final String blobStringCharset ) {
this ( allowReflection , delegate , paramName , indexOfFirstPeriod , specialType , blobStringCharset , 0 ) ;
}
SpecialVariableElement ( final VariableElement delegate , final SpecialType specialType , final String blobStringCharset , final int index ) {
this . delegate = delegate ;
SpecialVariableElement ( final boolean allowReflection , final VariableElement delegate , final String paramName , final int indexOfPeriod , final SpecialType specialType , final String blobStringCharset , final int index ) {
super ( delegate ) ;
this . allowReflection = allowReflection ;
this . specialType = specialType ;
this . blobStringCharset = blobStringCharset ;
this . index = index ;
this . name = getSimpleName ( ) . toString ( ) ;
this . iterable = specialType = = SpecialType . SQL & & JdbcMapperProcessor . types . isAssignable ( delegate . asType ( ) , JdbcMapperProcessor . iterableType ) ;
this . bindable = ! this . iterable & & specialType = = SpecialType . SQL & & JdbcMapperProcessor . types . isAssignable ( delegate . asType ( ) , JdbcMapperProcessor . bindableType ) ;
if ( indexOfPeriod = = - 1 ) {
// no recursion or anything complicated, straight parameter
this . name = paramName ;
this . type = delegate . asType ( ) ;
} else {
final String [ ] paramSplit = paramName . split ( "\\s*\\.\\s*" ) ;
if ( paramSplit . length < 2 ) {
JdbcMapperProcessor . messager . printMessage ( Diagnostic . Kind . ERROR , "paramName invalid with period at end: " + paramName , delegate ) ;
throw new RuntimeException ( "paramName invalid with period at end: " + paramName ) ;
}
final StringBuilder sb = new StringBuilder ( ) ;
appendVar ( paramSplit [ 0 ] , sb ) ;
this . type = delegate . asType ( ) ;
for ( int x = 1 ; x < paramSplit . length ; + + x ) {
appendVar ( paramSplit [ x ] , sb ) ;
}
this . name = sb . toString ( ) ;
}
this . iterable = specialType = = SpecialType . SQL & & types . isAssignable ( delegate . asType ( ) , JdbcMapperProcessor . iterableType ) ;
this . bindable = ! this . iterable & & specialType = = SpecialType . SQL & & types . isAssignable ( delegate . asType ( ) , JdbcMapperProcessor . bindableType ) ;
}
public void appendVar ( final String fullParam , final StringBuilder sb ) {
final boolean nullSafe = fullParam . endsWith ( "?" ) ;
final String param = nullSafe ? fullParam . substring ( 0 , fullParam . length ( ) - 1 ) : fullParam ;
// hack for first param
if ( type ! = null ) {
final String name = getGetterTypeAppendString ( param , sb ) ;
if ( name = = null ) {
JdbcMapperProcessor . messager . printMessage ( Diagnostic . Kind . ERROR , "recursive param not found: " + param , delegate ) ;
}
sb . append ( name ) ;
} else {
sb . append ( param ) ;
}
if ( nullSafe ) {
final String var = sb . toString ( ) ;
sb . setLength ( 0 ) ;
sb . append ( "((" ) . append ( var ) . append ( ") == null ? null : (" ) . append ( var ) . append ( "))" ) ;
}
}
public String getGetterTypeAppendString ( final String fieldName , final StringBuilder sb ) {
if ( type . getKind ( ) ! = TypeKind . DECLARED ) {
JdbcMapperProcessor . messager . printMessage ( Diagnostic . Kind . ERROR , "type " + type + " not TypeKind.DECLARED ?? how?? fieldName: " + fieldName , delegate ) ;
return "" ;
}
final DeclaredType declaredReturnType = ( DeclaredType ) type ;
final List < DeclaredType > allTypes = getAllImplementedTypes ( declaredReturnType , new ArrayList < DeclaredType > ( ) ) ;
// public methods
// have to loop to get super methods too
final String methodSuffix = Character . toUpperCase ( fieldName . charAt ( 0 ) ) + fieldName . substring ( 1 ) ;
final String getMethodName = "get" + methodSuffix , isMethodName = "is" + methodSuffix ;
for ( final DeclaredType clazz : allTypes ) {
for ( Element e : ( ( TypeElement ) clazz . asElement ( ) ) . getEnclosedElements ( ) ) {
if ( e . getKind ( ) ! = ElementKind . METHOD )
continue ;
final ExecutableElement m = ( ExecutableElement ) e ;
//System.out.printf("method: '%s', isSetterMethod: '%s'\n", m, isSetterMethod(m));
final String ret = matchingGetterMethod ( m , getMethodName , isMethodName ) ;
if ( ret ! = null ) {
return ret ;
}
}
}
// fix for 8813: include inherited and non-public fields
for ( final DeclaredType clazz : allTypes ) {
//System.out.println("fields in class: "+Arrays.toString(classFields));
for ( Element e : ( ( TypeElement ) clazz . asElement ( ) ) . getEnclosedElements ( ) ) {
if ( e . getKind ( ) ! = ElementKind . FIELD )
continue ;
final VariableElement f = ( VariableElement ) e ;
final Set < Modifier > modifiers = f . getModifiers ( ) ;
// we want the name to match exactly
if ( ! fieldName . equals ( f . getSimpleName ( ) . toString ( ) ) ) continue ;
// cannot be static
if ( modifiers . contains ( Modifier . STATIC ) ) return null ;
// must be public todo: what about package-private?
if ( modifiers . contains ( Modifier . PUBLIC ) ) {
this . type = f . asType ( ) ;
return "." + fieldName ;
}
if ( ! allowReflection ) {
JdbcMapperProcessor . messager . printMessage ( Diagnostic . Kind . ERROR , "cannot public setter, but did find non-public field on parameter: '" + delegate . getSimpleName ( ) + "' with this name: '" + fieldName + "', but reflection is not allowed" , delegate ) ;
return "" ;
}
// otherwise support terrible reflection
final TypeMirror oldType = this . type ;
this . type = f . asType ( ) ;
final String obj = sb . toString ( ) ;
sb . setLength ( 0 ) ;
return "com.moparisthebest.jdbc.util.ReflectionUtil.getValue(" + oldType . toString ( ) + ".class, \"" + fieldName + "\", " +
this . type . toString ( ) + ".class, (" + obj + "))" ;
}
}
JdbcMapperProcessor . messager . printMessage ( Diagnostic . Kind . ERROR , "cannot find field or public setter on parameter: '" + delegate . getSimpleName ( ) + "' with this name: '" + fieldName + "'" , delegate ) ;
return "" ;
}
/ * *
* Determine if the given method is a java bean setter method .
* @param method Method to check
* @param getMethodName
* @param isMethodName
* @return True if the method is a setter method .
* /
public String matchingGetterMethod ( final ExecutableElement method , final String getMethodName , final String isMethodName ) {
final String methodName = method . getSimpleName ( ) . toString ( ) ;
final boolean isMethod = isMethodName . equals ( methodName ) ;
if ( isMethod | | getMethodName . equals ( methodName ) ) {
final Set < Modifier > modifiers = method . getModifiers ( ) ;
// cannot be static
if ( modifiers . contains ( Modifier . STATIC ) ) return null ;
// must be public todo: what about package-private?
if ( ! modifiers . contains ( Modifier . PUBLIC ) ) return null ;
// must take no parameters
if ( method . getParameters ( ) . size ( ) ! = 0 ) return null ;
final TypeMirror ret = method . getReturnType ( ) ;
// must return boolean/Boolean to qualify for is*
if ( isMethod & & ! ( ret . getKind ( ) = = TypeKind . BOOLEAN | | types . isAssignable ( ret , booleanType ) ) ) return null ;
this . type = ret ;
return "." + methodName + "()" ;
}
return null ;
}
public String getName ( ) {
@ -66,75 +207,11 @@ class SpecialVariableElement implements VariableElement {
@@ -66,75 +207,11 @@ class SpecialVariableElement implements VariableElement {
this . componentTypeString = componentTypeString ;
}
@Override
public Object getConstantValue ( ) {
return delegate . getConstantValue ( ) ;
}
@Override
public TypeMirror asType ( ) {
return delegate . asType ( ) ;
}
@Override
public ElementKind getKind ( ) {
return delegate . getKind ( ) ;
}
@Override
public List < ? extends AnnotationMirror > getAnnotationMirrors ( ) {
return delegate . getAnnotationMirrors ( ) ;
return type ;
}
@Override
public < A extends Annotation > A getAnnotation ( final Class < A > annotationType ) {
return delegate . getAnnotation ( annotationType ) ;
}
@Override
public Set < Modifier > getModifiers ( ) {
return delegate . getModifiers ( ) ;
}
@Override
public Name getSimpleName ( ) {
return delegate . getSimpleName ( ) ;
}
@Override
public Element getEnclosingElement ( ) {
return delegate . getEnclosingElement ( ) ;
}
@Override
public List < ? extends Element > getEnclosedElements ( ) {
return delegate . getEnclosedElements ( ) ;
}
@Override
public boolean equals ( final Object obj ) {
return delegate . equals ( obj ) ;
}
@Override
public int hashCode ( ) {
return delegate . hashCode ( ) ;
}
@Override
public < R , P > R accept ( final ElementVisitor < R , P > v , final P p ) {
return delegate . accept ( v , p ) ;
}
//IFJAVA8_START
@Override
public < A extends Annotation > A [ ] getAnnotationsByType ( final Class < A > annotationType ) {
return delegate . getAnnotationsByType ( annotationType ) ;
}
//IFJAVA8_END
@Override
public String toString ( ) {
return "SpecialVariableElement{" +