signature:
public class BasePlugin { /** * Set the context under which this plugin is running .
 * @ param context the new context */
@ Override public void setContext ( Context context ) { } }

implementation:
super . setContext ( context ) ; // 添加插件
HookAggregator . getInstance ( ) . setContext ( context ) ; // 配置插件使用的模板引擎
PluginConfiguration cfg = PluginTools . getPluginConfiguration ( context , CommentPlugin . class ) ; if ( cfg == null || cfg . getProperty ( CommentPlugin . PRO_TEMPLATE ) == null ) { if ( context . getCommentGenerator ( ) instanceof DefaultCommentGenerator ) { // 使用默认模板引擎
commentGenerator = new TemplateCommentGenerator ( "default-comment.ftl" , true ) ; } else { // 用户自定义
commentGenerator = context . getCommentGenerator ( ) ; } } else { TemplateCommentGenerator templateCommentGenerator = new TemplateCommentGenerator ( cfg . getProperty ( CommentPlugin . PRO_TEMPLATE ) , false ) ; // ITFSW 插件使用的注释生成器
commentGenerator = templateCommentGenerator ; // 修正系统插件
try { // 先执行一次生成CommentGenerator操作 , 然后再替换
context . getCommentGenerator ( ) ; BeanUtils . setProperty ( context , "commentGenerator" , templateCommentGenerator ) ; } catch ( Exception e ) { logger . error ( "反射异常" , e ) ; } } // mybatis版本
if ( StringUtility . stringHasValue ( context . getProperty ( PRO_MYBATIS_VERSION ) ) ) { this . mybatisVersion = context . getProperty ( PRO_MYBATIS_VERSION ) ; }


signature:
public class BasePlugin { /** * { @ inheritDoc } */
@ Override public boolean validate ( List < String > warnings ) { } }

implementation:
this . warnings = warnings ; // 插件使用前提是targetRuntime为MyBatis3
if ( StringUtility . stringHasValue ( getContext ( ) . getTargetRuntime ( ) ) && "MyBatis3" . equalsIgnoreCase ( getContext ( ) . getTargetRuntime ( ) ) == false ) { warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "要求运行targetRuntime必须为MyBatis3！" ) ; return false ; } return true ;


signature:
public class BasePlugin { /** * { @ inheritDoc }
 * @ param introspectedTable */
@ Override public void initialized ( IntrospectedTable introspectedTable ) { } }

implementation:
super . initialized ( introspectedTable ) ; if ( StringUtility . stringHasValue ( introspectedTable . getTableConfiguration ( ) . getAlias ( ) ) ) { warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "请不要配置alias属性，这个属性官方支持也很混乱，导致插件支持会存在问题！" ) ; } PluginTools . getHook ( ITableConfigurationHook . class ) . tableConfiguration ( introspectedTable ) ; // mybatis版本
if ( StringUtility . stringHasValue ( this . getProperties ( ) . getProperty ( PRO_MYBATIS_VERSION ) ) ) { this . mybatisVersion = this . getProperties ( ) . getProperty ( PRO_MYBATIS_VERSION ) ; }


signature:
public class InnerTypeFullyQualifiedJavaType { /** * This method returns the fully qualified name - including any generic type parameters .
 * @ return Returns the fullyQualifiedName . */
@ Override public String getFullyQualifiedName ( ) { } }

implementation: String fullyQualifiedName = super . getFullyQualifiedName ( ) ; String before = fullyQualifiedName . substring ( 0 , fullyQualifiedName . lastIndexOf ( "." ) ) ; String end = fullyQualifiedName . substring ( fullyQualifiedName . lastIndexOf ( "." ) ) ; return before + "." + outerType + end ;


signature:
public class XmlElementGeneratorTools { /** * This method should return an XmlElement for the select key used to
 * automatically generate keys .
 * @ param introspectedColumn the column related to the select key statement
 * @ param generatedKey the generated key for the current table
 * @ return the selectKey element */
public static Element getSelectKey ( IntrospectedColumn introspectedColumn , GeneratedKey generatedKey ) { } }

implementation: return getSelectKey ( introspectedColumn , generatedKey , null ) ;


signature:
public class XmlElementGeneratorTools { /** * 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
 * @ param element
 * @ param introspectedTable
 * @ param prefix */
public static void useGeneratedKeys ( XmlElement element , IntrospectedTable introspectedTable , String prefix ) { } }

implementation:
GeneratedKey gk = introspectedTable . getGeneratedKey ( ) ; if ( gk != null ) { IntrospectedColumn introspectedColumn = IntrospectedTableTools . safeGetColumn ( introspectedTable , gk . getColumn ( ) ) ; // if the column is null , then it ' s a configuration error . The
// warning has already been reported
if ( introspectedColumn != null ) { // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
element . addAttribute ( new Attribute ( "useGeneratedKeys" , "true" ) ) ; element . addAttribute ( new Attribute ( "keyProperty" , ( prefix == null ? "" : prefix ) + introspectedColumn . getJavaProperty ( ) ) ) ; element . addAttribute ( new Attribute ( "keyColumn" , introspectedColumn . getActualColumnName ( ) ) ) ; } }


signature:
public class XmlElementGeneratorTools { /** * 生成keys Ele
 * @ param columns
 * @ param bracket
 * @ return */
public static List < Element > generateKeys ( List < IntrospectedColumn > columns , boolean bracket ) { } }

implementation: return generateCommColumns ( columns , null , bracket , 1 ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成keys Selective Ele
 * @ param columns
 * @ param prefix
 * @ return */
public static XmlElement generateKeysSelective ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateKeysSelective ( columns , prefix , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成keys Selective Ele
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ return */
public static XmlElement generateKeysSelective ( List < IntrospectedColumn > columns , String prefix , boolean bracket ) { } }

implementation: return generateCommColumnsSelective ( columns , prefix , bracket , 1 ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成values Ele
 * @ param columns
 * @ param prefix
 * @ return */
public static List < Element > generateValues ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateValues ( columns , prefix , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成values Ele
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ return */
public static List < Element > generateValues ( List < IntrospectedColumn > columns , String prefix , boolean bracket ) { } }

implementation: return generateCommColumns ( columns , prefix , bracket , 2 ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成values Selective Ele
 * @ param columns
 * @ param prefix
 * @ return */
public static XmlElement generateValuesSelective ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateValuesSelective ( columns , prefix , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成sets Ele
 * @ param columns
 * @ param prefix
 * @ return */
public static List < Element > generateSets ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateCommColumns ( columns , prefix , false , 3 ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成sets Selective Ele
 * @ param columns
 * @ param prefix
 * @ return */
public static XmlElement generateSetsSelective ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateCommColumnsSelective ( columns , prefix , false , 3 ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成keys Ele ( upsert )
 * @ param columns
 * @ param prefix
 * @ return */
public static List < Element > generateUpsertKeys ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateCommColumns ( columns , prefix , true , 1 , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成values Ele ( upsert )
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ return */
public static List < Element > generateUpsertValues ( List < IntrospectedColumn > columns , String prefix , boolean bracket ) { } }

implementation: return generateCommColumns ( columns , prefix , bracket , 2 , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成sets Ele ( upsert )
 * @ param columns
 * @ param prefix
 * @ return */
public static List < Element > generateUpsertSets ( List < IntrospectedColumn > columns , String prefix ) { } }

implementation: return generateCommColumns ( columns , prefix , false , 3 , true ) ;


signature:
public class XmlElementGeneratorTools { /** * 通用遍历columns
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ param type 1 : key , 2 : value , 3 : set
 * @ return */
private static List < Element > generateCommColumns ( List < IntrospectedColumn > columns , String prefix , boolean bracket , int type ) { } }

implementation: return generateCommColumns ( columns , prefix , bracket , type , false ) ;


signature:
public class XmlElementGeneratorTools { /** * 通用遍历columns
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ param type 1 : key , 2 : value , 3 : set
 * @ param upsert
 * @ return */
private static List < Element > generateCommColumns ( List < IntrospectedColumn > columns , String prefix , boolean bracket , int type , boolean upsert ) { } }

implementation:
List < Element > list = new ArrayList < > ( ) ; // 只有upsert插件才会传入 IdentityAndGeneratedAlwaysColumn
if ( upsert && hasIdentityAndGeneratedAlwaysColumns ( columns ) ) { XmlElement trimEle = generateTrim ( bracket ) ; for ( IntrospectedColumn introspectedColumn : columns ) { if ( introspectedColumn . isGeneratedAlways ( ) || introspectedColumn . isIdentity ( ) ) { generateSelectiveToTrimEleTo ( trimEle , introspectedColumn , prefix , type ) ; } else { generateSelectiveCommColumnTo ( trimEle , introspectedColumn , prefix , type ) ; } } return Arrays . asList ( trimEle ) ; } else { StringBuilder sb = new StringBuilder ( bracket ? "(" : "" ) ; Iterator < IntrospectedColumn > columnIterator = columns . iterator ( ) ; while ( columnIterator . hasNext ( ) ) { IntrospectedColumn introspectedColumn = columnIterator . next ( ) ; switch ( type ) { case 3 : List < Element > incrementEles = PluginTools . getHook ( IIncrementsPluginHook . class ) . incrementSetElementGenerated ( introspectedColumn , prefix , false ) ; if ( ! incrementEles . isEmpty ( ) ) { // 增量插件支持
if ( sb . length ( ) > 0 ) { list . add ( new TextElement ( sb . toString ( ) ) ) ; sb . setLength ( 0 ) ; } list . addAll ( incrementEles ) ; } else { sb . append ( MyBatis3FormattingUtilities . getEscapedColumnName ( introspectedColumn ) ) ; sb . append ( " = " ) ; sb . append ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , prefix ) ) ; } break ; case 2 : sb . append ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , prefix ) ) ; break ; case 1 : sb . append ( MyBatis3FormattingUtilities . getEscapedColumnName ( introspectedColumn ) ) ; break ; } if ( columnIterator . hasNext ( ) ) { sb . append ( ", " ) ; } // 保持和官方一致 80 进行换行
if ( type == 1 || type == 2 ) { if ( sb . length ( ) > 80 ) { list . add ( new TextElement ( sb . toString ( ) ) ) ; sb . setLength ( 0 ) ; OutputUtilities . xmlIndent ( sb , 1 ) ; } } else { list . add ( new TextElement ( sb . toString ( ) ) ) ; sb . setLength ( 0 ) ; } } if ( sb . length ( ) > 0 || bracket ) { list . add ( new TextElement ( sb . append ( bracket ? ")" : "" ) . toString ( ) ) ) ; } return list ; }


signature:
public class XmlElementGeneratorTools { /** * 通用遍历columns
 * @ param columns
 * @ param prefix
 * @ param bracket
 * @ param type 1 : key , 2 : value , 3 : set
 * @ return */
private static XmlElement generateCommColumnsSelective ( List < IntrospectedColumn > columns , String prefix , boolean bracket , int type ) { } }

implementation: XmlElement trimEle = generateTrim ( bracket ) ; for ( IntrospectedColumn introspectedColumn : columns ) { generateSelectiveToTrimEleTo ( trimEle , introspectedColumn , prefix , type ) ; } return trimEle ;


signature:
public class XmlElementGeneratorTools { /** * trim 节点
 * @ param bracket
 * @ return */
private static XmlElement generateTrim ( boolean bracket ) { } }

implementation: XmlElement trimEle = new XmlElement ( "trim" ) ; if ( bracket ) { trimEle . addAttribute ( new Attribute ( "prefix" , "(" ) ) ; trimEle . addAttribute ( new Attribute ( "suffix" , ")" ) ) ; trimEle . addAttribute ( new Attribute ( "suffixOverrides" , "," ) ) ; } else { trimEle . addAttribute ( new Attribute ( "suffixOverrides" , "," ) ) ; } return trimEle ;


signature:
public class XmlElementGeneratorTools { /** * 生成选择列到trim 节点
 * @ param trimEle
 * @ param introspectedColumn
 * @ param prefix
 * @ param type 1 : key , 2 : value , 3 : set */
private static void generateSelectiveToTrimEleTo ( XmlElement trimEle , IntrospectedColumn introspectedColumn , String prefix , int type ) { } }

implementation:
if ( type != 3 && ( introspectedColumn . isSequenceColumn ( ) || introspectedColumn . getFullyQualifiedJavaType ( ) . isPrimitive ( ) ) ) { // if it is a sequence column , it is not optional
// This is required for MyBatis3 because MyBatis3 parses
// and calculates the SQL before executing the selectKey
// if it is primitive , we cannot do a null check
generateSelectiveCommColumnTo ( trimEle , introspectedColumn , prefix , type ) ; } else { XmlElement eleIf = new XmlElement ( "if" ) ; eleIf . addAttribute ( new Attribute ( "test" , introspectedColumn . getJavaProperty ( prefix ) + " != null" ) ) ; generateSelectiveCommColumnTo ( eleIf , introspectedColumn , prefix , type ) ; trimEle . addElement ( eleIf ) ; }


signature:
public class XmlElementGeneratorTools { /** * 生成
 * @ param element
 * @ param introspectedColumn
 * @ param prefix
 * @ param type 1 : key , 2 : value , 3 : set */
private static void generateSelectiveCommColumnTo ( XmlElement element , IntrospectedColumn introspectedColumn , String prefix , int type ) { } }

implementation:
switch ( type ) { case 3 : List < Element > incrementEles = PluginTools . getHook ( IIncrementsPluginHook . class ) . incrementSetElementGenerated ( introspectedColumn , prefix , true ) ; if ( ! incrementEles . isEmpty ( ) ) { // 增量插件支持
for ( Element ele : incrementEles ) { element . addElement ( ele ) ; } } else { element . addElement ( new TextElement ( MyBatis3FormattingUtilities . getEscapedColumnName ( introspectedColumn ) + " = " + MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , prefix ) + "," ) ) ; } break ; case 2 : element . addElement ( new TextElement ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , prefix ) + "," ) ) ; break ; case 1 : element . addElement ( new TextElement ( MyBatis3FormattingUtilities . getEscapedColumnName ( introspectedColumn ) + "," ) ) ; break ; }


signature:
public class XmlElementGeneratorTools { /** * 生成 xxxByPrimaryKey 的where 语句
 * @ param element
 * @ param primaryKeyColumns
 * @ return */
public static void generateWhereByPrimaryKeyTo ( XmlElement element , List < IntrospectedColumn > primaryKeyColumns ) { } }

implementation: generateWhereByPrimaryKeyTo ( element , primaryKeyColumns , null ) ;


signature:
public class XmlElementGeneratorTools { /** * 生成 xxxByPrimaryKey 的where 语句
 * @ param element
 * @ param primaryKeyColumns
 * @ param prefix
 * @ return */
public static void generateWhereByPrimaryKeyTo ( XmlElement element , List < IntrospectedColumn > primaryKeyColumns , String prefix ) { } }

implementation: StringBuilder sb = new StringBuilder ( ) ; boolean and = false ; for ( IntrospectedColumn introspectedColumn : primaryKeyColumns ) { sb . setLength ( 0 ) ; if ( and ) { sb . append ( "  and " ) ; } else { sb . append ( "where " ) ; and = true ; } sb . append ( MyBatis3FormattingUtilities . getEscapedColumnName ( introspectedColumn ) ) ; sb . append ( " = " ) ; sb . append ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , prefix ) ) ; element . addElement ( new TextElement ( sb . toString ( ) ) ) ; }


signature:
public class XmlElementGeneratorTools { /** * 是否存在自增或者生成的column
 * @ param columns
 * @ return */
private static boolean hasIdentityAndGeneratedAlwaysColumns ( List < IntrospectedColumn > columns ) { } }

implementation: for ( IntrospectedColumn ic : columns ) { if ( ic . isGeneratedAlways ( ) || ic . isIdentity ( ) ) { return true ; } } return false ;


signature:
public class XmlElementGeneratorTools { /** * 生成resultMap的result 节点
 * @ param name
 * @ param introspectedColumn
 * @ return */
public static XmlElement generateResultMapResultElement ( String name , IntrospectedColumn introspectedColumn ) { } }

implementation: XmlElement resultElement = new XmlElement ( name ) ; resultElement . addAttribute ( new Attribute ( "column" , MyBatis3FormattingUtilities . getRenamedColumnNameForResultMap ( introspectedColumn ) ) ) ; resultElement . addAttribute ( new Attribute ( "property" , introspectedColumn . getJavaProperty ( ) ) ) ; resultElement . addAttribute ( new Attribute ( "jdbcType" , introspectedColumn . getJdbcTypeName ( ) ) ) ; if ( stringHasValue ( introspectedColumn . getTypeHandler ( ) ) ) { resultElement . addAttribute ( new Attribute ( "typeHandler" , introspectedColumn . getTypeHandler ( ) ) ) ; } return resultElement ;


signature:
public class XmlElementGeneratorTools { /** * 生成逻辑删除列的删除值
 * @ param logicalDeleteColumn
 * @ param value
 * @ return */
public static String generateLogicalDeleteColumnValue ( IntrospectedColumn logicalDeleteColumn , String value ) { } }

implementation:
StringBuilder sb = new StringBuilder ( ) ; // 判断字段类型
if ( value == null || "NULL" . equalsIgnoreCase ( value ) ) { sb . append ( "NULL" ) ; } else if ( logicalDeleteColumn . isStringColumn ( ) ) { sb . append ( "'" ) ; sb . append ( value ) ; sb . append ( "'" ) ; } else if ( logicalDeleteColumn . getFullyQualifiedJavaType ( ) . getFullyQualifiedName ( ) . equals ( Long . class . getName ( ) ) ) { sb . append ( value . replaceAll ( "L|l" , "" ) ) ; } else if ( logicalDeleteColumn . getFullyQualifiedJavaType ( ) . getFullyQualifiedName ( ) . equals ( Float . class . getName ( ) ) ) { sb . append ( value . replaceAll ( "F|f" , "" ) ) ; } else { sb . append ( value ) ; } return sb . toString ( ) ;


signature:
public class PluginTools { /** * 检查插件依赖
 * @ param context 上下文
 * @ param plugins 插件
 * @ return */
public static boolean checkDependencyPlugin ( Context context , Class ... plugins ) { } }

implementation: for ( Class plugin : plugins ) { if ( getPluginIndex ( context , plugin ) < 0 ) { return false ; } } return true ;


signature:
public class PluginTools { /** * 获取插件所在位置
 * @ param context 上下文
 * @ param plugin 插件
 * @ return - 1 : 未找到 */
public static int getPluginIndex ( Context context , Class plugin ) { } }

implementation:
List < PluginConfiguration > list = getConfigPlugins ( context ) ; // 检查是否配置了ModelColumnPlugin插件
for ( int i = 0 ; i < list . size ( ) ; i ++ ) { PluginConfiguration config = list . get ( i ) ; if ( plugin . getName ( ) . equals ( config . getConfigurationType ( ) ) ) { return i ; } } return - 1 ;


signature:
public class PluginTools { /** * 获取插件列表
 * @ param ctx 上下文
 * @ return */
public static List < PluginConfiguration > getConfigPlugins ( Context ctx ) { } }

implementation:
try { // 利用反射获取pluginConfigurations属性
return ( List < PluginConfiguration > ) BeanUtils . getProperty ( ctx , "pluginConfigurations" ) ; } catch ( Exception e ) { logger . error ( "插件检查反射异常" , e ) ; } return new ArrayList < > ( ) ;


signature:
public class PluginTools { /** * 获取插件配置
 * @ param context 上下文
 * @ param plugin 插件
 * @ return */
public static PluginConfiguration getPluginConfiguration ( Context context , Class plugin ) { } }

implementation: int index = getPluginIndex ( context , plugin ) ; if ( index > - 1 ) { return getConfigPlugins ( context ) . get ( index ) ; } return null ;


signature:
public class PluginTools { /** * 版本号比较
 * @ param v1
 * @ param v2
 * @ return 0代表相等 , 1代表左边大 , - 1代表右边大
 * Utils . compareVersion ( " 1.0.358_20180820090554 " , " 1.0.358_20180820090553 " ) = 1 */
public static int compareVersion ( String v1 , String v2 ) { } }

implementation: if ( v1 . equals ( v2 ) ) { return 0 ; } String [ ] version1Array = v1 . split ( "[._]" ) ; String [ ] version2Array = v2 . split ( "[._]" ) ; int index = 0 ; int minLen = Math . min ( version1Array . length , version2Array . length ) ; long diff = 0 ; while ( index < minLen && ( diff = Long . parseLong ( version1Array [ index ] ) - Long . parseLong ( version2Array [ index ] ) ) == 0 ) { index ++ ; } if ( diff == 0 ) { for ( int i = index ; i < version1Array . length ; i ++ ) { if ( Long . parseLong ( version1Array [ i ] ) > 0 ) { return 1 ; } } for ( int i = index ; i < version2Array . length ; i ++ ) { if ( Long . parseLong ( version2Array [ i ] ) > 0 ) { return - 1 ; } } return 0 ; } else { return diff > 0 ? 1 : - 1 ; }


signature:
public class TableRenamePlugin { /** * { @ inheritDoc } */
@ Override public boolean validate ( List < String > warnings ) { } }

implementation:
// 如果配置了searchString 或者 replaceString , 二者不允许单独存在
if ( ( getProperties ( ) . getProperty ( PRO_SEARCH_STRING ) == null && getProperties ( ) . getProperty ( PRO_REPLACE_STRING ) != null ) || ( getProperties ( ) . getProperty ( PRO_SEARCH_STRING ) != null && getProperties ( ) . getProperty ( PRO_REPLACE_STRING ) == null ) ) { warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "插件的searchString、replaceString属性需配合使用，不能单独存在！" ) ; return false ; } // 如果table配置了domainObjectName或者mapperName就不要再启动该插件了
for ( TableConfiguration tableConfiguration : context . getTableConfigurations ( ) ) { if ( tableConfiguration . getDomainObjectName ( ) != null || tableConfiguration . getMapperName ( ) != null ) { warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "插件请不要配合table的domainObjectName或者mapperName一起使用！" ) ; return false ; } } return super . validate ( warnings ) ;


signature:
public class TableRenamePlugin { /** * 初始化阶段
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param introspectedTable
 * @ return */
@ Override public void initialized ( IntrospectedTable introspectedTable ) { } }

implementation:
// 1 . 获取表单独配置
if ( introspectedTable . getTableConfigurationProperty ( PRO_TABLE_OVERRIDE ) != null ) { String override = introspectedTable . getTableConfigurationProperty ( PRO_TABLE_OVERRIDE ) ; try { IntrospectedTableTools . setDomainObjectName ( introspectedTable , getContext ( ) , override ) ; } catch ( Exception e ) { logger . error ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "使用tableOverride替换时异常！" , e ) ; } } else if ( getProperties ( ) . getProperty ( PRO_SEARCH_STRING ) != null ) { String searchString = getProperties ( ) . getProperty ( PRO_SEARCH_STRING ) ; String replaceString = getProperties ( ) . getProperty ( PRO_REPLACE_STRING ) ; String domainObjectName = introspectedTable . getFullyQualifiedTable ( ) . getDomainObjectName ( ) ; Pattern pattern = Pattern . compile ( searchString ) ; Matcher matcher = pattern . matcher ( domainObjectName ) ; domainObjectName = matcher . replaceAll ( replaceString ) ; // 命名规范化 首字母大写
domainObjectName = FormatTools . upFirstChar ( domainObjectName ) ; try { IntrospectedTableTools . setDomainObjectName ( introspectedTable , getContext ( ) , domainObjectName ) ; } catch ( Exception e ) { logger . error ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "使用searchString、replaceString替换时异常！" , e ) ; } } super . initialized ( introspectedTable ) ;


signature:
public class FormatTools { /** * 在最佳位置添加方法
 * @ param interfacz
 * @ param method */
public static void addMethodWithBestPosition ( Interface interfacz , Method method ) { } }

implementation:
// import
Set < FullyQualifiedJavaType > importTypes = new TreeSet < > ( ) ; // 返回
if ( method . getReturnType ( ) != null ) { importTypes . add ( method . getReturnType ( ) ) ; importTypes . addAll ( method . getReturnType ( ) . getTypeArguments ( ) ) ; } // 参数 比较特殊的是ModelColumn生成的Column
for ( Parameter parameter : method . getParameters ( ) ) { boolean flag = true ; for ( String annotation : parameter . getAnnotations ( ) ) { if ( annotation . startsWith ( "@Param" ) ) { importTypes . add ( new FullyQualifiedJavaType ( "org.apache.ibatis.annotations.Param" ) ) ; if ( annotation . matches ( ".*selective.*" ) && parameter . getType ( ) . getShortName ( ) . equals ( ModelColumnPlugin . ENUM_NAME ) ) { flag = false ; } } } if ( flag ) { importTypes . add ( parameter . getType ( ) ) ; importTypes . addAll ( parameter . getType ( ) . getTypeArguments ( ) ) ; } } interfacz . addImportedTypes ( importTypes ) ; addMethodWithBestPosition ( method , interfacz . getMethods ( ) ) ;


signature:
public class FormatTools { /** * 在最佳位置添加节点
 * @ param rootElement
 * @ param element */
public static void addElementWithBestPosition ( XmlElement rootElement , XmlElement element ) { } }

implementation:
// sql 元素都放在sql后面
if ( element . getName ( ) . equals ( "sql" ) ) { int index = 0 ; for ( Element ele : rootElement . getElements ( ) ) { if ( ele instanceof XmlElement && ( ( XmlElement ) ele ) . getName ( ) . equals ( "sql" ) ) { index ++ ; } } rootElement . addElement ( index , element ) ; } else { // 根据id 排序
String id = getIdFromElement ( element ) ; if ( id == null ) { rootElement . addElement ( element ) ; } else { List < Element > elements = rootElement . getElements ( ) ; int index = - 1 ; for ( int i = 0 ; i < elements . size ( ) ; i ++ ) { Element ele = elements . get ( i ) ; if ( ele instanceof XmlElement ) { String eleId = getIdFromElement ( ( XmlElement ) ele ) ; if ( eleId != null ) { if ( eleId . startsWith ( id ) ) { if ( index == - 1 ) { index = i ; } } else if ( id . startsWith ( eleId ) ) { index = i + 1 ; } } } } if ( index == - 1 || index >= elements . size ( ) ) { rootElement . addElement ( element ) ; } else { elements . add ( index , element ) ; } } }


signature:
public class FormatTools { /** * 找出节点ID值
 * @ param element
 * @ return */
private static String getIdFromElement ( XmlElement element ) { } }

implementation: for ( Attribute attribute : element . getAttributes ( ) ) { if ( attribute . getName ( ) . equals ( "id" ) ) { return attribute . getValue ( ) ; } } return null ;


signature:
public class FormatTools { /** * 获取最佳添加位置
 * @ param method
 * @ param methods
 * @ return */
private static void addMethodWithBestPosition ( Method method , List < Method > methods ) { } }

implementation: int index = - 1 ; for ( int i = 0 ; i < methods . size ( ) ; i ++ ) { Method m = methods . get ( i ) ; if ( m . getName ( ) . equals ( method . getName ( ) ) ) { if ( m . getParameters ( ) . size ( ) <= method . getParameters ( ) . size ( ) ) { index = i + 1 ; } else { index = i ; } } else if ( m . getName ( ) . startsWith ( method . getName ( ) ) ) { if ( index == - 1 ) { index = i ; } } else if ( method . getName ( ) . startsWith ( m . getName ( ) ) ) { index = i + 1 ; } } if ( index == - 1 || index >= methods . size ( ) ) { methods . add ( methods . size ( ) , method ) ; } else { methods . add ( index , method ) ; }


signature:
public class FormatTools { /** * 替换已有方法注释
 * @ param commentGenerator
 * @ param method
 * @ param introspectedTable */
public static void replaceGeneralMethodComment ( CommentGenerator commentGenerator , Method method , IntrospectedTable introspectedTable ) { } }

implementation: method . getJavaDocLines ( ) . clear ( ) ; commentGenerator . addGeneralMethodComment ( method , introspectedTable ) ;


signature:
public class FormatTools { /** * 替换已有注释
 * @ param commentGenerator
 * @ param element */
public static void replaceComment ( CommentGenerator commentGenerator , XmlElement element ) { } }

implementation: Iterator < Element > elementIterator = element . getElements ( ) . iterator ( ) ; boolean flag = false ; while ( elementIterator . hasNext ( ) ) { Element ele = elementIterator . next ( ) ; if ( ele instanceof TextElement && ( ( TextElement ) ele ) . getContent ( ) . matches ( ".*<!--.*" ) ) { flag = true ; } if ( flag ) { elementIterator . remove ( ) ; } if ( ele instanceof TextElement && ( ( TextElement ) ele ) . getContent ( ) . matches ( ".*-->.*" ) ) { flag = false ; } } XmlElement tmpEle = new XmlElement ( "tmp" ) ; commentGenerator . addComment ( tmpEle ) ; for ( int i = tmpEle . getElements ( ) . size ( ) - 1 ; i >= 0 ; i -- ) { element . addElement ( 0 , tmpEle . getElements ( ) . get ( i ) ) ; }


signature:
public class BatchInsertPlugin { /** * Java Client Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param interfaze
 * @ param topLevelClass
 * @ param introspectedTable
 * @ return */
@ Override public boolean clientGenerated ( Interface interfaze , TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) { } }

implementation:
// 1 . batchInsert
FullyQualifiedJavaType listType = FullyQualifiedJavaType . getNewListInstance ( ) ; listType . addTypeArgument ( introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) ) ; Method mBatchInsert = JavaElementGeneratorTools . generateMethod ( METHOD_BATCH_INSERT , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( listType , "list" , "@Param(\"list\")" ) ) ; commentGenerator . addGeneralMethodComment ( mBatchInsert , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mBatchInsert ) ; logger . debug ( "itfsw(批量插入插件):" + interfaze . getType ( ) . getShortName ( ) + "增加batchInsert方法。" ) ; // 2 . batchInsertSelective
FullyQualifiedJavaType selectiveType = new FullyQualifiedJavaType ( introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) . getShortName ( ) + "." + ModelColumnPlugin . ENUM_NAME ) ; Method mBatchInsertSelective = JavaElementGeneratorTools . generateMethod ( METHOD_BATCH_INSERT_SELECTIVE , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( listType , "list" , "@Param(\"list\")" ) , new Parameter ( selectiveType , "selective" , "@Param(\"selective\")" , true ) ) ; commentGenerator . addGeneralMethodComment ( mBatchInsertSelective , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mBatchInsertSelective ) ; logger . debug ( "itfsw(批量插入插件):" + interfaze . getType ( ) . getShortName ( ) + "增加batchInsertSelective方法。" ) ; return true ;


signature:
public class BatchInsertPlugin { /** * SQL Map Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param document
 * @ param introspectedTable
 * @ return */
@ Override public boolean sqlMapDocumentGenerated ( Document document , IntrospectedTable introspectedTable ) { } }

implementation:
// 1 . batchInsert
XmlElement batchInsertEle = new XmlElement ( "insert" ) ; batchInsertEle . addAttribute ( new Attribute ( "id" , METHOD_BATCH_INSERT ) ) ; // 参数类型
batchInsertEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( batchInsertEle ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
XmlElementGeneratorTools . useGeneratedKeys ( batchInsertEle , introspectedTable ) ; batchInsertEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; for ( Element element : XmlElementGeneratorTools . generateKeys ( ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) , true ) ) { batchInsertEle . addElement ( element ) ; } // 添加foreach节点
XmlElement foreachElement = new XmlElement ( "foreach" ) ; foreachElement . addAttribute ( new Attribute ( "collection" , "list" ) ) ; foreachElement . addAttribute ( new Attribute ( "item" , "item" ) ) ; foreachElement . addAttribute ( new Attribute ( "separator" , "," ) ) ; for ( Element element : XmlElementGeneratorTools . generateValues ( ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) , "item." ) ) { foreachElement . addElement ( element ) ; } // values 构建
batchInsertEle . addElement ( new TextElement ( "values" ) ) ; batchInsertEle . addElement ( foreachElement ) ; document . getRootElement ( ) . addElement ( batchInsertEle ) ; logger . debug ( "itfsw(批量插入插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加batchInsert实现方法。" ) ; // 2 . batchInsertSelective
XmlElement batchInsertSelectiveEle = new XmlElement ( "insert" ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( batchInsertSelectiveEle ) ; batchInsertSelectiveEle . addAttribute ( new Attribute ( "id" , METHOD_BATCH_INSERT_SELECTIVE ) ) ; // 参数类型
batchInsertSelectiveEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
// issues # 70 mybatis 版本升级到3.5.0之后 , useGeneratedKeys在配置keyProperty时需要指定前缀
XmlElementGeneratorTools . useGeneratedKeys ( batchInsertSelectiveEle , introspectedTable , PluginTools . compareVersion ( mybatisVersion , "3.5.0" ) >= 0 ? "list." : null ) ; // 支持原生字段非空判断
if ( this . allowMultiQueries ) { XmlElement chooseEle = new XmlElement ( "choose" ) ; // selective 增强
XmlElement selectiveEnhancedEle = new XmlElement ( "when" ) ; selectiveEnhancedEle . addAttribute ( new Attribute ( "test" , "selective != null and selective.length > 0" ) ) ; chooseEle . addElement ( selectiveEnhancedEle ) ; selectiveEnhancedEle . getElements ( ) . addAll ( this . generateSelectiveEnhancedEles ( introspectedTable ) ) ; // 原生非空判断语句
XmlElement selectiveNormalEle = new XmlElement ( "otherwise" ) ; chooseEle . addElement ( selectiveNormalEle ) ; XmlElement foreachEle = new XmlElement ( "foreach" ) ; selectiveNormalEle . addElement ( foreachEle ) ; foreachEle . addAttribute ( new Attribute ( "collection" , "list" ) ) ; foreachEle . addAttribute ( new Attribute ( "item" , "item" ) ) ; foreachEle . addAttribute ( new Attribute ( "separator" , ";" ) ) ; foreachEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; XmlElement insertTrimElement = new XmlElement ( "trim" ) ; foreachEle . addElement ( insertTrimElement ) ; insertTrimElement . addElement ( XmlElementGeneratorTools . generateKeysSelective ( ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) , "item." ) ) ; foreachEle . addElement ( new TextElement ( "values" ) ) ; XmlElement valuesTrimElement = new XmlElement ( "trim" ) ; foreachEle . addElement ( valuesTrimElement ) ; valuesTrimElement . addElement ( XmlElementGeneratorTools . generateValuesSelective ( ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) , "item." ) ) ; batchInsertSelectiveEle . addElement ( chooseEle ) ; } else { batchInsertSelectiveEle . getElements ( ) . addAll ( this . generateSelectiveEnhancedEles ( introspectedTable ) ) ; } document . getRootElement ( ) . addElement ( batchInsertSelectiveEle ) ; logger . debug ( "itfsw(批量插入插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加batchInsertSelective实现方法。" ) ; return true ;


signature:
public class BatchInsertPlugin { /** * 生成insert selective 增强的插入语句
 * @ param introspectedTable
 * @ return */
private List < Element > generateSelectiveEnhancedEles ( IntrospectedTable introspectedTable ) { } }

implementation:
List < Element > eles = new ArrayList < > ( ) ; eles . add ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) + " (" ) ) ; XmlElement foreachInsertColumns = new XmlElement ( "foreach" ) ; foreachInsertColumns . addAttribute ( new Attribute ( "collection" , "selective" ) ) ; foreachInsertColumns . addAttribute ( new Attribute ( "item" , "column" ) ) ; foreachInsertColumns . addAttribute ( new Attribute ( "separator" , "," ) ) ; foreachInsertColumns . addElement ( new TextElement ( "${column.escapedColumnName}" ) ) ; eles . add ( foreachInsertColumns ) ; eles . add ( new TextElement ( ")" ) ) ; // values
eles . add ( new TextElement ( "values" ) ) ; // foreach values
XmlElement foreachValues = new XmlElement ( "foreach" ) ; foreachValues . addAttribute ( new Attribute ( "collection" , "list" ) ) ; foreachValues . addAttribute ( new Attribute ( "item" , "item" ) ) ; foreachValues . addAttribute ( new Attribute ( "separator" , "," ) ) ; foreachValues . addElement ( new TextElement ( "(" ) ) ; // foreach 所有插入的列 , 比较是否存在
XmlElement foreachInsertColumnsCheck = new XmlElement ( "foreach" ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "collection" , "selective" ) ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "item" , "column" ) ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "separator" , "," ) ) ; // 所有表字段
List < IntrospectedColumn > columns = ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) ; List < IntrospectedColumn > columns1 = ListUtilities . removeIdentityAndGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) ; for ( int i = 0 ; i < columns1 . size ( ) ; i ++ ) { IntrospectedColumn introspectedColumn = columns . get ( i ) ; XmlElement check = new XmlElement ( "if" ) ; check . addAttribute ( new Attribute ( "test" , "'" + introspectedColumn . getActualColumnName ( ) + "'.toString() == column.value" ) ) ; check . addElement ( new TextElement ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , "item." ) ) ) ; foreachInsertColumnsCheck . addElement ( check ) ; } foreachValues . addElement ( foreachInsertColumnsCheck ) ; foreachValues . addElement ( new TextElement ( ")" ) ) ; eles . add ( foreachValues ) ; return eles ;


signature:
public class InnerInterfaceWrapperToInnerClass { /** * 重写获取Java内容方法 , 调用InnerInterface的实现
 * @ param indentLevel
 * @ param compilationUnit
 * @ return */
@ Override public String getFormattedContent ( int indentLevel , CompilationUnit compilationUnit ) { } }

implementation: return this . innerInterface . getFormattedContent ( indentLevel , compilationUnit ) ;


signature:
public class XmlElementTools { /** * 获取属性
 * @ param element
 * @ param name */
public static Attribute getAttribute ( XmlElement element , String name ) { } }

implementation: Iterator < Attribute > iterator = element . getAttributes ( ) . iterator ( ) ; while ( iterator . hasNext ( ) ) { Attribute attribute = iterator . next ( ) ; if ( attribute . getName ( ) . equals ( name ) ) { return attribute ; } } return null ;


signature:
public class XmlElementTools { /** * 移除属性
 * @ param element
 * @ param name */
public static void removeAttribute ( XmlElement element , String name ) { } }

implementation: Iterator < Attribute > iterator = element . getAttributes ( ) . iterator ( ) ; while ( iterator . hasNext ( ) ) { Attribute attribute = iterator . next ( ) ; if ( attribute . getName ( ) . equals ( name ) ) { iterator . remove ( ) ; } }


signature:
public class XmlElementTools { /** * 替换属性
 * @ param element
 * @ param attribute */
public static void replaceAttribute ( XmlElement element , Attribute attribute ) { } }

implementation: removeAttribute ( element , attribute . getName ( ) ) ; element . addAttribute ( attribute ) ;


signature:
public class XmlElementTools { /** * xmlElement 替换
 * @ param srcEle
 * @ param destEle */
public static void replaceXmlElement ( XmlElement srcEle , XmlElement destEle ) { } }

implementation: srcEle . setName ( destEle . getName ( ) ) ; srcEle . getAttributes ( ) . clear ( ) ; srcEle . getAttributes ( ) . addAll ( destEle . getAttributes ( ) ) ; srcEle . getElements ( ) . clear ( ) ; srcEle . getElements ( ) . addAll ( destEle . getElements ( ) ) ;


signature:
public class XmlElementTools { /** * 查找指定xml节点下指定节点名称的元素
 * @ param xmlElement
 * @ param name
 * @ return */
public static List < XmlElement > findXmlElements ( XmlElement xmlElement , String name ) { } }

implementation: List < XmlElement > list = new ArrayList < > ( ) ; List < Element > elements = xmlElement . getElements ( ) ; for ( Element ele : elements ) { if ( ele instanceof XmlElement ) { XmlElement xmlElement1 = ( XmlElement ) ele ; if ( name . equalsIgnoreCase ( xmlElement1 . getName ( ) ) ) { list . add ( xmlElement1 ) ; } } } return list ;


signature:
public class XmlElementTools { /** * 查询指定xml下所有text xml 节点
 * @ param xmlElement
 * @ return */
public static List < TextElement > findAllTextElements ( XmlElement xmlElement ) { } }

implementation: List < TextElement > textElements = new ArrayList < > ( ) ; for ( Element element : xmlElement . getElements ( ) ) { if ( element instanceof XmlElement ) { textElements . addAll ( findAllTextElements ( ( XmlElement ) element ) ) ; } else if ( element instanceof TextElement ) { textElements . add ( ( TextElement ) element ) ; } } return textElements ;


signature:
public class ModelBuilderPlugin { /** * Model Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param topLevelClass
 * @ param introspectedTable
 * @ return */
@ Override public boolean modelBaseRecordClassGenerated ( TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) { } }

implementation:
// 判断是否有生成Model的WithBLOBs类
List < IntrospectedColumn > columns = introspectedTable . getRules ( ) . generateRecordWithBLOBsClass ( ) ? introspectedTable . getNonBLOBColumns ( ) : introspectedTable . getAllColumns ( ) ; InnerClass innerClass = this . generateModelBuilder ( topLevelClass , introspectedTable , columns ) ; topLevelClass . addInnerClass ( innerClass ) ; return super . modelBaseRecordClassGenerated ( topLevelClass , introspectedTable ) ;


signature:
public class ModelBuilderPlugin { /** * Model Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param topLevelClass
 * @ param introspectedTable
 * @ return */
@ Override public boolean modelRecordWithBLOBsClassGenerated ( TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) { } }

implementation: InnerClass innerClass = this . generateModelBuilder ( topLevelClass , introspectedTable , introspectedTable . getAllColumns ( ) ) ; topLevelClass . addInnerClass ( innerClass ) ; return super . modelRecordWithBLOBsClassGenerated ( topLevelClass , introspectedTable ) ;


signature:
public class ModelBuilderPlugin { /** * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param topLevelClass
 * @ param introspectedTable
 * @ return */
@ Override public boolean modelPrimaryKeyClassGenerated ( TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) { } }

implementation: InnerClass innerClass = this . generateModelBuilder ( topLevelClass , introspectedTable , introspectedTable . getPrimaryKeyColumns ( ) ) ; topLevelClass . addInnerClass ( innerClass ) ; return super . modelPrimaryKeyClassGenerated ( topLevelClass , introspectedTable ) ;


signature:
public class ModelBuilderPlugin { /** * 生成ModelBuilder
 * @ param topLevelClass
 * @ param introspectedTable
 * @ param columns
 * @ return */
private InnerClass generateModelBuilder ( TopLevelClass topLevelClass , IntrospectedTable introspectedTable , List < IntrospectedColumn > columns ) { } }

implementation:
// 生成内部Builder类
InnerClass innerClass = new InnerClass ( BUILDER_CLASS_NAME ) ; innerClass . setVisibility ( JavaVisibility . PUBLIC ) ; innerClass . setStatic ( true ) ; // 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
// 顺序为 key base withBLOBs
InnerTypeFullyQualifiedJavaType builderType = new InnerTypeFullyQualifiedJavaType ( topLevelClass . getType ( ) . getFullyQualifiedName ( ) + "." + BUILDER_CLASS_NAME ) ; if ( innerClasses . get ( introspectedTable ) != null ) { innerClass . setSuperClass ( innerClasses . get ( introspectedTable ) ) ; innerClasses . remove ( introspectedTable ) ; } innerClasses . put ( introspectedTable , builderType ) ; // 增加静态builder方法实现和lombok一样
Method builder = JavaElementGeneratorTools . generateMethod ( "builder" , JavaVisibility . PUBLIC , builderType ) ; commentGenerator . addGeneralMethodComment ( builder , introspectedTable ) ; builder . setStatic ( true ) ; builder . addBodyLine ( "return new " + builderType . getShortName ( ) + "();" ) ; FormatTools . addMethodWithBestPosition ( topLevelClass , builder ) ; commentGenerator . addClassComment ( innerClass , introspectedTable ) ; logger . debug ( "itfsw(数据Model链式构建插件):" + topLevelClass . getType ( ) . getShortName ( ) + "增加内部Builder类。" ) ; // 构建内部obj变量
Field f = JavaElementGeneratorTools . generateField ( "obj" , JavaVisibility . PRIVATE , topLevelClass . getType ( ) , null ) ; commentGenerator . addFieldComment ( f , introspectedTable ) ; innerClass . addField ( f ) ; // 构造构造方法
Method constructor = new Method ( BUILDER_CLASS_NAME ) ; constructor . setVisibility ( JavaVisibility . PUBLIC ) ; constructor . setConstructor ( true ) ; constructor . addBodyLine ( new StringBuilder ( "this.obj = new " ) . append ( topLevelClass . getType ( ) . getShortName ( ) ) . append ( "();" ) . toString ( ) ) ; commentGenerator . addGeneralMethodComment ( constructor , introspectedTable ) ; FormatTools . addMethodWithBestPosition ( innerClass , constructor ) ; logger . debug ( "itfsw(数据Model链式构建插件):" + topLevelClass . getType ( ) . getShortName ( ) + ".Builder增加的构造方法。" ) ; for ( IntrospectedColumn introspectedColumn : columns ) { Field field = JavaBeansUtil . getJavaBeansField ( introspectedColumn , context , introspectedTable ) ; Method setterMethod = JavaBeansUtil . getJavaBeansSetter ( introspectedColumn , context , introspectedTable ) ; Method method = JavaElementGeneratorTools . generateMethod ( field . getName ( ) , JavaVisibility . PUBLIC , innerClass . getType ( ) , new Parameter ( field . getType ( ) , field . getName ( ) ) ) ; commentGenerator . addSetterComment ( method , introspectedTable , introspectedColumn ) ; method = JavaElementGeneratorTools . generateMethodBody ( method , "obj." + setterMethod . getName ( ) + "(" + field . getName ( ) + ");" , "return this;" ) ; // hook
if ( PluginTools . getHook ( IModelBuilderPluginHook . class ) . modelBuilderSetterMethodGenerated ( method , topLevelClass , innerClass , introspectedColumn , introspectedTable ) ) { FormatTools . addMethodWithBestPosition ( innerClass , method ) ; logger . debug ( "itfsw(数据Model链式构建插件):" + topLevelClass . getType ( ) . getShortName ( ) + ".Builder增加" + method . getName ( ) + "方法(复合主键)。" ) ; } } Method build = JavaElementGeneratorTools . generateMethod ( "build" , JavaVisibility . PUBLIC , topLevelClass . getType ( ) ) ; build . addBodyLine ( "return this.obj;" ) ; commentGenerator . addGeneralMethodComment ( build , introspectedTable ) ; FormatTools . addMethodWithBestPosition ( innerClass , build ) ; logger . debug ( "itfsw(数据Model链式构建插件):" + topLevelClass . getType ( ) . getShortName ( ) + ".Builder增加build方法。" ) ; // hook
PluginTools . getHook ( IModelBuilderPluginHook . class ) . modelBuilderClassGenerated ( topLevelClass , innerClass , columns , introspectedTable ) ; return innerClass ;


signature:
public class ExampleTargetPlugin { /** * { @ inheritDoc } */
@ Override public boolean validate ( List < String > warnings ) { } }

implementation:
// 获取配置的目标package
Properties properties = getProperties ( ) ; this . targetPackage = properties . getProperty ( PRO_TARGET_PACKAGE ) ; if ( this . targetPackage == null ) { warnings . add ( "请配置com.itfsw.mybatis.generator.plugins.ExampleTargetPlugin插件的目标包名(targetPackage)！" ) ; return false ; } return super . validate ( warnings ) ;


signature:
public class ExampleTargetPlugin { /** * 初始化阶段
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param introspectedTable */
@ Override public void initialized ( IntrospectedTable introspectedTable ) { } }

implementation:
super . initialized ( introspectedTable ) ; String exampleType = introspectedTable . getExampleType ( ) ; // 修改包名
Context context = getContext ( ) ; JavaModelGeneratorConfiguration configuration = context . getJavaModelGeneratorConfiguration ( ) ; String targetPackage = configuration . getTargetPackage ( ) ; String newExampleType = exampleType . replace ( targetPackage , this . targetPackage ) ; introspectedTable . setExampleType ( newExampleType ) ; logger . debug ( "itfsw(Example 目标包修改插件):修改" + introspectedTable . getExampleType ( ) + "的包到" + this . targetPackage ) ;


signature:
public class TableRenameConfigurationPlugin { /** * { @ inheritDoc }
 * @ param warnings
 * @ return */
@ Override public boolean validate ( List < String > warnings ) { } }

implementation:
Properties properties = this . getProperties ( ) ; this . tableSearchString = properties . getProperty ( PRO_TABLE_SEARCH_STRING ) ; this . tableReplaceString = properties . getProperty ( PRO_TABLE_REPLACE_STRING ) ; this . columnSearchString = properties . getProperty ( PRO_COLUMN_SEARCH_STRING ) ; this . columnReplaceString = properties . getProperty ( PRO_COLUMN_REPLACE_STRING ) ; // 和官方行为保持一致
this . exampleSuffix = properties . getProperty ( PRO_EXAMPLE_SUFFIX ) ; this . clientSuffix = properties . getProperty ( PRO_CLIENT_SUFFIX ) ; this . modelSuffix = properties . getProperty ( PRO_MODEL_SUFFIX ) ; return super . validate ( warnings ) ;


signature:
public class TableRenameConfigurationPlugin { /** * 表配置
 * @ param introspectedTable */
@ Override public void tableConfiguration ( IntrospectedTable introspectedTable ) { } }

implementation:
try { TableConfiguration tableConfiguration = introspectedTable . getTableConfiguration ( ) ; FullyQualifiedTable fullyQualifiedTable = introspectedTable . getFullyQualifiedTable ( ) ; String tableReplaceDisable = tableConfiguration . getProperty ( PRO_TABLE_REPLACE_DISABLE ) ; this . tableReplaceDisable = tableReplaceDisable == null ? false : StringUtility . isTrue ( tableReplaceDisable ) ; String columnReplaceDisable = tableConfiguration . getProperty ( PRO_COLUMN_REPLACE_DISABLE ) ; this . columnReplaceDisable = columnReplaceDisable == null ? false : StringUtility . isTrue ( columnReplaceDisable ) ; String javaClientInterfacePackage = ( String ) BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateJavaClientInterfacePackage" ) ; String sqlMapPackage = ( String ) BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateSqlMapPackage" ) ; String javaModelPackage = ( String ) BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateJavaModelPackage" ) ; // - - - - - table 重命名 - - - - -
if ( tableConfiguration . getDomainObjectRenamingRule ( ) == null && this . tableSearchString != null && ! this . tableReplaceDisable ) { DomainObjectRenamingRule rule = new DomainObjectRenamingRule ( ) ; rule . setSearchString ( this . tableSearchString ) ; rule . setReplaceString ( this . tableReplaceString ) ; tableConfiguration . setDomainObjectRenamingRule ( rule ) ; BeanUtils . setProperty ( introspectedTable . getFullyQualifiedTable ( ) , "domainObjectRenamingRule" , rule ) ; // 重新初始化一下属性
BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateJavaClientAttributes" ) ; BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateModelAttributes" ) ; BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateXmlAttributes" ) ; } // TODO 官方bug临时修复
if ( tableConfiguration . getDomainObjectRenamingRule ( ) != null ) { String domainObjectName = fullyQualifiedTable . getDomainObjectName ( ) ; // 首字母大写
BeanUtils . setProperty ( fullyQualifiedTable , "domainObjectName" , getCamelCaseString ( domainObjectName , true ) ) ; // 重新初始化一下属性
BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateJavaClientAttributes" ) ; BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateModelAttributes" ) ; BeanUtils . invoke ( introspectedTable , IntrospectedTable . class , "calculateXmlAttributes" ) ; } // - - - - - column 重命名 - - - - -
if ( tableConfiguration . getColumnRenamingRule ( ) == null && this . columnSearchString != null && ! this . columnReplaceDisable ) { ColumnRenamingRule rule = new ColumnRenamingRule ( ) ; rule . setSearchString ( this . columnSearchString ) ; rule . setReplaceString ( this . columnReplaceString ) ; tableConfiguration . setColumnRenamingRule ( rule ) ; // introspectedTable 使用到的所有column过滤并替换
this . renameColumns ( introspectedTable . getAllColumns ( ) , rule , tableConfiguration ) ; } // - - - - - 后缀修正 - - - - -
// 1 . client
if ( this . clientSuffix != null ) { // mapper
StringBuilder sb = new StringBuilder ( ) ; sb . append ( javaClientInterfacePackage ) ; sb . append ( '.' ) ; if ( stringHasValue ( tableConfiguration . getMapperName ( ) ) ) { sb . append ( tableConfiguration . getMapperName ( ) ) ; } else { if ( stringHasValue ( fullyQualifiedTable . getDomainObjectSubPackage ( ) ) ) { sb . append ( fullyQualifiedTable . getDomainObjectSubPackage ( ) ) ; sb . append ( '.' ) ; } sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( this . clientSuffix ) ; } introspectedTable . setMyBatis3JavaMapperType ( sb . toString ( ) ) ; // xml mapper namespace
sb . setLength ( 0 ) ; sb . append ( sqlMapPackage ) ; sb . append ( '.' ) ; if ( stringHasValue ( tableConfiguration . getMapperName ( ) ) ) { sb . append ( tableConfiguration . getMapperName ( ) ) ; } else { sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( this . clientSuffix ) ; } introspectedTable . setMyBatis3FallbackSqlMapNamespace ( sb . toString ( ) ) ; // xml file
sb . setLength ( 0 ) ; sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( this . clientSuffix ) ; sb . append ( ".xml" ) ; introspectedTable . setMyBatis3XmlMapperFileName ( sb . toString ( ) ) ; } // 2 . example
if ( this . exampleSuffix != null ) { StringBuilder sb = new StringBuilder ( ) ; sb . append ( javaModelPackage ) ; sb . append ( '.' ) ; sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( this . exampleSuffix ) ; introspectedTable . setExampleType ( sb . toString ( ) ) ; } // 3 . model
if ( this . modelSuffix != null ) { StringBuilder sb = new StringBuilder ( ) ; sb . append ( javaModelPackage ) ; sb . append ( '.' ) ; sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( "Key" ) ; sb . append ( this . modelSuffix ) ; introspectedTable . setPrimaryKeyType ( sb . toString ( ) ) ; sb . setLength ( 0 ) ; sb . append ( javaModelPackage ) ; sb . append ( '.' ) ; sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( this . modelSuffix ) ; introspectedTable . setBaseRecordType ( sb . toString ( ) ) ; sb . setLength ( 0 ) ; sb . append ( javaModelPackage ) ; sb . append ( '.' ) ; sb . append ( fullyQualifiedTable . getDomainObjectName ( ) ) ; sb . append ( "WithBLOBs" ) ; sb . append ( this . modelSuffix ) ; introspectedTable . setRecordWithBLOBsType ( sb . toString ( ) ) ; } } catch ( Exception e ) { e . printStackTrace ( ) ; }


signature:
public class TableRenameConfigurationPlugin { /** * column rename
 * @ param columns
 * @ param rule
 * @ param tc */
private void renameColumns ( List < IntrospectedColumn > columns , ColumnRenamingRule rule , TableConfiguration tc ) { } }

implementation: Pattern pattern = Pattern . compile ( rule . getSearchString ( ) ) ; String replaceString = rule . getReplaceString ( ) ; replaceString = replaceString == null ? "" : replaceString ; for ( IntrospectedColumn introspectedColumn : columns ) { String calculatedColumnName ; if ( pattern == null ) { calculatedColumnName = introspectedColumn . getActualColumnName ( ) ; } else { Matcher matcher = pattern . matcher ( introspectedColumn . getActualColumnName ( ) ) ; calculatedColumnName = matcher . replaceAll ( replaceString ) ; } if ( isTrue ( tc . getProperty ( PropertyRegistry . TABLE_USE_ACTUAL_COLUMN_NAMES ) ) ) { introspectedColumn . setJavaProperty ( getValidPropertyName ( calculatedColumnName ) ) ; } else if ( isTrue ( tc . getProperty ( PropertyRegistry . TABLE_USE_COMPOUND_PROPERTY_NAMES ) ) ) { StringBuilder sb = new StringBuilder ( ) ; sb . append ( calculatedColumnName ) ; sb . append ( '_' ) ; sb . append ( getCamelCaseString ( introspectedColumn . getRemarks ( ) , true ) ) ; introspectedColumn . setJavaProperty ( getValidPropertyName ( sb . toString ( ) ) ) ; } else { introspectedColumn . setJavaProperty ( getCamelCaseString ( calculatedColumnName , false ) ) ; } }


signature:
public class UpsertPlugin { /** * { @ inheritDoc } */
@ Override public boolean validate ( List < String > warnings ) { } }

implementation:
// 插件使用前提是数据库为MySQL
if ( "com.mysql.jdbc.Driver" . equalsIgnoreCase ( this . getContext ( ) . getJdbcConnectionConfiguration ( ) . getDriverClass ( ) ) == false && "com.mysql.cj.jdbc.Driver" . equalsIgnoreCase ( this . getContext ( ) . getJdbcConnectionConfiguration ( ) . getDriverClass ( ) ) == false ) { warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "插件使用前提是数据库为MySQL！" ) ; return false ; } // 插件是否开启了多sql提交
Properties properties = this . getProperties ( ) ; String allowMultiQueries = properties . getProperty ( PRO_ALLOW_MULTI_QUERIES ) ; this . allowMultiQueries = allowMultiQueries == null ? false : StringUtility . isTrue ( allowMultiQueries ) ; if ( this . allowMultiQueries ) { // 提示用户注意信息
warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "插件您开启了allowMultiQueries支持，注意在jdbc url 配置中增加“allowMultiQueries=true”支持（不怎么建议使用该功能，开启多sql提交会增加sql注入的风险，请确保你所有sql都使用MyBatis书写，请不要使用statement进行sql提交）！" ) ; } // 是否允许批量
String allowBatchUpsert = properties . getProperty ( PRO_ALLOW_BATCH_UPSERT ) ; this . allowBatchUpsert = allowBatchUpsert == null ? false : StringUtility . isTrue ( allowBatchUpsert ) ; // 批量时依赖插件 ModelColumnPlugin
if ( this . allowBatchUpsert && ! PluginTools . checkDependencyPlugin ( context , ModelColumnPlugin . class ) ) { // 提示用户注意信息
warnings . add ( "itfsw:插件" + this . getClass ( ) . getTypeName ( ) + "插件您开启了allowBatchUpsert支持，请配置依赖的插件" + ModelColumnPlugin . class . getTypeName ( ) + "！" ) ; } return super . validate ( warnings ) ;


signature:
public class UpsertPlugin { /** * Java Client Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param interfaze
 * @ param topLevelClass
 * @ param introspectedTable
 * @ return */
@ Override public boolean clientGenerated ( Interface interfaze , TopLevelClass topLevelClass , IntrospectedTable introspectedTable ) { } }

implementation:
// = = = = = upsert = = = = =
Method mUpsert = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( JavaElementGeneratorTools . getModelTypeWithoutBLOBs ( introspectedTable ) , "record" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsert , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsert ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsert方法。" ) ; // = = = = = upsertWithBLOBs = = = = =
// ! ! ! 注意这里的行为不以有没有生成Model 的 WithBLOBs类为基准
if ( introspectedTable . hasBLOBColumns ( ) ) { Method mUpsertWithBLOBs = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT_WITH_BLOBS , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( JavaElementGeneratorTools . getModelTypeWithBLOBs ( introspectedTable ) , "record" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsertWithBLOBs , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsertWithBLOBs ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsertWithBLOBs方法。" ) ; } // = = = = = upsertSelective = = = = =
// 找出全字段对应的Model
FullyQualifiedJavaType fullFieldModel = introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) ; Method mUpsertSelective = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT_SELECTIVE , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( fullFieldModel , "record" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsertSelective , introspectedTable ) ; // hook
if ( PluginTools . getHook ( IUpsertPluginHook . class ) . clientUpsertSelectiveMethodGenerated ( mUpsertSelective , interfaze , introspectedTable ) ) { // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsertSelective ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsertSelective方法。" ) ; } if ( this . allowMultiQueries ) { // = = = = = upsertByExample = = = = =
Method mUpsertByExample = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT_BY_EXAMPLE , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( JavaElementGeneratorTools . getModelTypeWithoutBLOBs ( introspectedTable ) , "record" , "@Param(\"record\")" ) , new Parameter ( new FullyQualifiedJavaType ( introspectedTable . getExampleType ( ) ) , "example" , "@Param(\"example\")" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsertByExample , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsertByExample ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsertByExample方法。" ) ; // = = = = = upsertByExampleWithBLOBs = = = = =
// ! ! ! 注意这里的行为不以有没有生成Model 的 WithBLOBs类为基准
if ( introspectedTable . hasBLOBColumns ( ) ) { Method mUpsertByExampleWithBLOBs = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT_BY_EXAMPLE_WITH_BLOBS , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( JavaElementGeneratorTools . getModelTypeWithBLOBs ( introspectedTable ) , "record" , "@Param(\"record\")" ) , new Parameter ( new FullyQualifiedJavaType ( introspectedTable . getExampleType ( ) ) , "example" , "@Param(\"example\")" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsertByExampleWithBLOBs , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsertByExampleWithBLOBs ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsertByExampleWithBLOBs方法。" ) ; } // = = = = = upsertByExampleSelective = = = = =
Method mUpsertByExampleSelective = JavaElementGeneratorTools . generateMethod ( METHOD_UPSERT_BY_EXAMPLE_SELECTIVE , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) , "record" , "@Param(\"record\")" ) , new Parameter ( new FullyQualifiedJavaType ( introspectedTable . getExampleType ( ) ) , "example" , "@Param(\"example\")" ) ) ; commentGenerator . addGeneralMethodComment ( mUpsertByExampleSelective , introspectedTable ) ; // hook
if ( PluginTools . getHook ( IUpsertPluginHook . class ) . clientUpsertByExampleSelectiveMethodGenerated ( mUpsertByExampleSelective , interfaze , introspectedTable ) ) { // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mUpsertByExampleSelective ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加upsertByExampleSelective方法。" ) ; } } if ( this . allowBatchUpsert ) { // = = = = = batchUpsert = = = = =
FullyQualifiedJavaType returnType = FullyQualifiedJavaType . getNewListInstance ( ) ; returnType . addTypeArgument ( JavaElementGeneratorTools . getModelTypeWithoutBLOBs ( introspectedTable ) ) ; Method mBatchUpsert = JavaElementGeneratorTools . generateMethod ( METHOD_BATCH_UPSERT , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( returnType , "list" , "@Param(\"list\")" ) ) ; commentGenerator . addGeneralMethodComment ( mBatchUpsert , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mBatchUpsert ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加batchUpsert方法。" ) ; // = = = = = batchUpsertWithBLOBs = = = = =
// ! ! ! 注意这里的行为不以有没有生成Model 的 WithBLOBs类为基准
if ( introspectedTable . hasBLOBColumns ( ) ) { returnType = FullyQualifiedJavaType . getNewListInstance ( ) ; returnType . addTypeArgument ( JavaElementGeneratorTools . getModelTypeWithBLOBs ( introspectedTable ) ) ; Method mBatchUpsertWithBLOBs = JavaElementGeneratorTools . generateMethod ( METHOD_BATCH_UPSERT_WITH_BLOBS , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( returnType , "list" , "@Param(\"list\")" ) ) ; commentGenerator . addGeneralMethodComment ( mBatchUpsertWithBLOBs , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mBatchUpsertWithBLOBs ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加batchUpsertWithBLOBs方法。" ) ; } // = = = = = batchUpsertSelective = = = = =
returnType = FullyQualifiedJavaType . getNewListInstance ( ) ; returnType . addTypeArgument ( fullFieldModel ) ; FullyQualifiedJavaType selectiveType = new FullyQualifiedJavaType ( introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) . getShortName ( ) + "." + ModelColumnPlugin . ENUM_NAME ) ; Method mBatchUpsertSelective = JavaElementGeneratorTools . generateMethod ( METHOD_BATCH_UPSERT_SELECTIVE , JavaVisibility . DEFAULT , FullyQualifiedJavaType . getIntInstance ( ) , new Parameter ( returnType , "list" , "@Param(\"list\")" ) , new Parameter ( selectiveType , "selective" , "@Param(\"selective\")" , true ) ) ; commentGenerator . addGeneralMethodComment ( mBatchUpsertSelective , introspectedTable ) ; // interface 增加方法
FormatTools . addMethodWithBestPosition ( interfaze , mBatchUpsertSelective ) ; logger . debug ( "itfsw(存在即更新插件):" + interfaze . getType ( ) . getShortName ( ) + "增加batchUpsertSelective方法。" ) ; } return super . clientGenerated ( interfaze , topLevelClass , introspectedTable ) ;


signature:
public class UpsertPlugin { /** * SQL Map Methods 生成
 * 具体执行顺序 http : / / www . mybatis . org / generator / reference / pluggingIn . html
 * @ param document
 * @ param introspectedTable
 * @ return */
@ Override public boolean sqlMapDocumentGenerated ( Document document , IntrospectedTable introspectedTable ) { } }

implementation: this . generateXmlElementWithSelective ( document , introspectedTable ) ; this . generateXmlElement ( document , introspectedTable , false ) ; if ( introspectedTable . hasBLOBColumns ( ) ) { this . generateXmlElement ( document , introspectedTable , true ) ; } if ( this . allowBatchUpsert ) { this . generateBatchXmlElementSelective ( document , introspectedTable ) ; this . generateBatchXmlElement ( document , introspectedTable , false ) ; if ( introspectedTable . hasBLOBColumns ( ) ) { this . generateBatchXmlElement ( document , introspectedTable , true ) ; } } return super . sqlMapDocumentGenerated ( document , introspectedTable ) ;


signature:
public class UpsertPlugin { /** * 批量
 * @ param document
 * @ param introspectedTable */
private void generateBatchXmlElementSelective ( Document document , IntrospectedTable introspectedTable ) { } }

implementation:
XmlElement insertEle = new XmlElement ( "insert" ) ; insertEle . addAttribute ( new Attribute ( "id" , METHOD_BATCH_UPSERT_SELECTIVE ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( insertEle ) ; // 参数类型
insertEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
// XmlElementGeneratorTools . useGeneratedKeys ( insertEle , introspectedTable , " list . " ) ;
// insert
insertEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) + " (" ) ) ; XmlElement foreachInsertColumns = new XmlElement ( "foreach" ) ; foreachInsertColumns . addAttribute ( new Attribute ( "collection" , "selective" ) ) ; foreachInsertColumns . addAttribute ( new Attribute ( "item" , "column" ) ) ; foreachInsertColumns . addAttribute ( new Attribute ( "separator" , "," ) ) ; foreachInsertColumns . addElement ( new TextElement ( "${column.escapedColumnName}" ) ) ; insertEle . addElement ( foreachInsertColumns ) ; insertEle . addElement ( new TextElement ( ")" ) ) ; // values
insertEle . addElement ( new TextElement ( "values" ) ) ; // foreach values
XmlElement foreachValues = new XmlElement ( "foreach" ) ; foreachValues . addAttribute ( new Attribute ( "collection" , "list" ) ) ; foreachValues . addAttribute ( new Attribute ( "item" , "item" ) ) ; foreachValues . addAttribute ( new Attribute ( "separator" , "," ) ) ; foreachValues . addElement ( new TextElement ( "(" ) ) ; // foreach 所有插入的列 , 比较是否存在
XmlElement foreachInsertColumnsCheck = new XmlElement ( "foreach" ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "collection" , "selective" ) ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "item" , "column" ) ) ; foreachInsertColumnsCheck . addAttribute ( new Attribute ( "separator" , "," ) ) ; // 所有表字段
List < IntrospectedColumn > columns = ListUtilities . removeGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) ; for ( int i = 0 ; i < columns . size ( ) ; i ++ ) { IntrospectedColumn introspectedColumn = columns . get ( i ) ; XmlElement check = new XmlElement ( "if" ) ; check . addAttribute ( new Attribute ( "test" , "'" + introspectedColumn . getActualColumnName ( ) + "'.toString() == column.value" ) ) ; check . addElement ( new TextElement ( MyBatis3FormattingUtilities . getParameterClause ( introspectedColumn , "item." ) ) ) ; foreachInsertColumnsCheck . addElement ( check ) ; } foreachValues . addElement ( foreachInsertColumnsCheck ) ; foreachValues . addElement ( new TextElement ( ")" ) ) ; insertEle . addElement ( foreachValues ) ; insertEle . addElement ( new TextElement ( "on duplicate key update " ) ) ; // set
XmlElement foreachSetColumns = new XmlElement ( "foreach" ) ; insertEle . addElement ( foreachSetColumns ) ; foreachSetColumns . addAttribute ( new Attribute ( "collection" , "selective" ) ) ; foreachSetColumns . addAttribute ( new Attribute ( "item" , "column" ) ) ; foreachSetColumns . addAttribute ( new Attribute ( "separator" , "," ) ) ; foreachSetColumns . addElement ( new TextElement ( "${column.escapedColumnName} = values(${column.escapedColumnName})" ) ) ; document . getRootElement ( ) . addElement ( insertEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加batchUpsertSelective实现方法。" ) ;


signature:
public class UpsertPlugin { /** * 批量
 * @ param document
 * @ param introspectedTable
 * @ param withBLOBs */
private void generateBatchXmlElement ( Document document , IntrospectedTable introspectedTable , boolean withBLOBs ) { } }

implementation:
List < IntrospectedColumn > columns = ListUtilities . removeGeneratedAlwaysColumns ( withBLOBs ? introspectedTable . getAllColumns ( ) : introspectedTable . getNonBLOBColumns ( ) ) ; XmlElement insertEle = new XmlElement ( "insert" ) ; insertEle . addAttribute ( new Attribute ( "id" , withBLOBs ? METHOD_BATCH_UPSERT_WITH_BLOBS : METHOD_BATCH_UPSERT ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( insertEle ) ; // 参数类型
insertEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
// XmlElementGeneratorTools . useGeneratedKeys ( insertEle , introspectedTable ) ;
// insert
insertEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; for ( Element element : XmlElementGeneratorTools . generateKeys ( columns , true ) ) { insertEle . addElement ( element ) ; } insertEle . addElement ( new TextElement ( "values" ) ) ; // values
XmlElement foreachEle = new XmlElement ( "foreach" ) ; insertEle . addElement ( foreachEle ) ; foreachEle . addAttribute ( new Attribute ( "collection" , "list" ) ) ; foreachEle . addAttribute ( new Attribute ( "item" , "item" ) ) ; foreachEle . addAttribute ( new Attribute ( "separator" , "," ) ) ; for ( Element element : XmlElementGeneratorTools . generateValues ( columns , "item." , true ) ) { foreachEle . addElement ( element ) ; } insertEle . addElement ( new TextElement ( "on duplicate key update " ) ) ; // set
Iterator < IntrospectedColumn > columnIterator = columns . iterator ( ) ; while ( columnIterator . hasNext ( ) ) { IntrospectedColumn column = columnIterator . next ( ) ; insertEle . addElement ( new TextElement ( MyBatis3FormattingUtilities . getEscapedColumnName ( column ) + " = values(" + MyBatis3FormattingUtilities . getEscapedColumnName ( column ) + ")" + ( columnIterator . hasNext ( ) ? "," : "" ) ) ) ; } document . getRootElement ( ) . addElement ( insertEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加" + ( withBLOBs ? "batchUpsertWithBLOBs" : "batchUpsert" ) + "实现方法。" ) ;


signature:
public class UpsertPlugin { /** * 当Selective情况
 * @ param document
 * @ param introspectedTable */
private void generateXmlElementWithSelective ( Document document , IntrospectedTable introspectedTable ) { } }

implementation:
List < IntrospectedColumn > columns = ListUtilities . removeGeneratedAlwaysColumns ( introspectedTable . getAllColumns ( ) ) ; // = = = = = upsertSelective = = = = =
XmlElement insertEle = new XmlElement ( "insert" ) ; insertEle . addAttribute ( new Attribute ( "id" , METHOD_UPSERT_SELECTIVE ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( insertEle ) ; // 参数类型
insertEle . addAttribute ( new Attribute ( "parameterType" , introspectedTable . getRules ( ) . calculateAllFieldsClass ( ) . getFullyQualifiedName ( ) ) ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
XmlElementGeneratorTools . useGeneratedKeys ( insertEle , introspectedTable ) ; // insert
insertEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; XmlElement insertColumnsEle = XmlElementGeneratorTools . generateKeysSelective ( columns ) ; insertEle . addElement ( insertColumnsEle ) ; insertEle . addElement ( new TextElement ( "values" ) ) ; XmlElement insertValuesEle = XmlElementGeneratorTools . generateValuesSelective ( columns ) ; insertEle . addElement ( insertValuesEle ) ; insertEle . addElement ( new TextElement ( "on duplicate key update " ) ) ; // set
XmlElement setsEle = XmlElementGeneratorTools . generateSetsSelective ( columns ) ; insertEle . addElement ( setsEle ) ; // hook
if ( PluginTools . getHook ( IUpsertPluginHook . class ) . sqlMapUpsertSelectiveElementGenerated ( insertEle , columns , insertColumnsEle , insertValuesEle , setsEle , introspectedTable ) ) { document . getRootElement ( ) . addElement ( insertEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加upsertSelective实现方法。" ) ; } if ( this . allowMultiQueries ) { // = = = = = upsertByExampleSelective = = = = =
XmlElement updateEle = new XmlElement ( "update" ) ; updateEle . addAttribute ( new Attribute ( "id" , METHOD_UPSERT_BY_EXAMPLE_SELECTIVE ) ) ; // 参数类型
updateEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( updateEle ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
// XmlElementGeneratorTools . useGeneratedKeys ( updateEle , introspectedTable , " record . " ) ;
// upsertByExample 先执行的update , 所以没法获取id
// update
updateEle . addElement ( new TextElement ( "update " + introspectedTable . getAliasedFullyQualifiedTableNameAtRuntime ( ) ) ) ; updateEle . addElement ( new TextElement ( "set" ) ) ; // set 操作增加增量插件支持
setsEle = XmlElementGeneratorTools . generateSetsSelective ( columns , "record." ) ; updateEle . addElement ( setsEle ) ; // update where
updateEle . addElement ( XmlElementGeneratorTools . getUpdateByExampleIncludeElement ( introspectedTable ) ) ; // multiQueries
updateEle . addElement ( new TextElement ( ";" ) ) ; // insert
updateEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; insertColumnsEle = XmlElementGeneratorTools . generateKeysSelective ( columns , "record." ) ; updateEle . addElement ( insertColumnsEle ) ; insertValuesEle = XmlElementGeneratorTools . generateValuesSelective ( columns , "record." , false ) ; // 查询值
this . generateExistsClause ( introspectedTable , updateEle , Arrays . asList ( insertValuesEle ) ) ; // hook
if ( PluginTools . getHook ( IUpsertPluginHook . class ) . sqlMapUpsertByExampleSelectiveElementGenerated ( updateEle , columns , insertColumnsEle , insertValuesEle , setsEle , introspectedTable ) ) { document . getRootElement ( ) . addElement ( updateEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加upsertSelective实现方法。" ) ; } }


signature:
public class UpsertPlugin { /** * 生成xml
 * @ param document
 * @ param introspectedTable
 * @ param withBLOBs */
private void generateXmlElement ( Document document , IntrospectedTable introspectedTable , boolean withBLOBs ) { } }

implementation:
List < IntrospectedColumn > columns = ListUtilities . removeGeneratedAlwaysColumns ( withBLOBs ? introspectedTable . getAllColumns ( ) : introspectedTable . getNonBLOBColumns ( ) ) ; // = = = = = upsert = = = = =
XmlElement insertEle = new XmlElement ( "insert" ) ; insertEle . addAttribute ( new Attribute ( "id" , withBLOBs ? METHOD_UPSERT_WITH_BLOBS : METHOD_UPSERT ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( insertEle ) ; // 参数类型
insertEle . addAttribute ( new Attribute ( "parameterType" , withBLOBs ? JavaElementGeneratorTools . getModelTypeWithBLOBs ( introspectedTable ) . getFullyQualifiedName ( ) : JavaElementGeneratorTools . getModelTypeWithoutBLOBs ( introspectedTable ) . getFullyQualifiedName ( ) ) ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
XmlElementGeneratorTools . useGeneratedKeys ( insertEle , introspectedTable ) ; // insert
insertEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; for ( Element element : XmlElementGeneratorTools . generateUpsertKeys ( columns , null ) ) { insertEle . addElement ( element ) ; } insertEle . addElement ( new TextElement ( "values" ) ) ; for ( Element element : XmlElementGeneratorTools . generateUpsertValues ( columns , null , true ) ) { insertEle . addElement ( element ) ; } insertEle . addElement ( new TextElement ( "on duplicate key update " ) ) ; // set
for ( Element set : XmlElementGeneratorTools . generateUpsertSets ( columns , null ) ) { insertEle . addElement ( set ) ; } document . getRootElement ( ) . addElement ( insertEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加" + ( withBLOBs ? "upsertWithBLOBs" : "upsert" ) + "实现方法。" ) ; if ( this . allowMultiQueries ) { // = = = = = upsertByExample = = = = =
XmlElement updateEle = new XmlElement ( "update" ) ; updateEle . addAttribute ( new Attribute ( "id" , withBLOBs ? METHOD_UPSERT_BY_EXAMPLE_WITH_BLOBS : METHOD_UPSERT_BY_EXAMPLE ) ) ; // 参数类型
updateEle . addAttribute ( new Attribute ( "parameterType" , "map" ) ) ; // 添加注释 ( ! ! ! 必须添加注释 , overwrite覆盖生成时 , @ see XmlFileMergerJaxp . isGeneratedNode会去判断注释中是否存在OLD _ ELEMENT _ TAGS中的一点 , 例子 : @ mbg . generated )
commentGenerator . addComment ( updateEle ) ; // 使用JDBC的getGenereatedKeys方法获取主键并赋值到keyProperty设置的领域模型属性中 。 所以只支持MYSQL和SQLServer
// XmlElementGeneratorTools . useGeneratedKeys ( updateEle , introspectedTable , " record . " ) ;
// upsertByExample 先执行的update , 所以没法获取id
// update
updateEle . addElement ( new TextElement ( "update " + introspectedTable . getAliasedFullyQualifiedTableNameAtRuntime ( ) ) ) ; updateEle . addElement ( new TextElement ( "set" ) ) ; // set
for ( Element set : XmlElementGeneratorTools . generateUpsertSets ( columns , "record." ) ) { updateEle . addElement ( set ) ; } // update where
updateEle . addElement ( XmlElementGeneratorTools . getUpdateByExampleIncludeElement ( introspectedTable ) ) ; // multiQueries
updateEle . addElement ( new TextElement ( ";" ) ) ; // insert
updateEle . addElement ( new TextElement ( "insert into " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; for ( Element element : XmlElementGeneratorTools . generateUpsertKeys ( columns , "record." ) ) { updateEle . addElement ( element ) ; } this . generateExistsClause ( introspectedTable , updateEle , XmlElementGeneratorTools . generateUpsertValues ( columns , "record." , false ) ) ; document . getRootElement ( ) . addElement ( updateEle ) ; logger . debug ( "itfsw(存在即更新插件):" + introspectedTable . getMyBatis3XmlMapperFileName ( ) + "增加" + ( withBLOBs ? "upsertByExampleWithBLOBs" : "upsertByExample" ) + "实现方法。" ) ; }


signature:
public class UpsertPlugin { /** * exists 语句
 * + 635
 * @ param introspectedTable
 * @ param element
 * @ param values */
private void generateExistsClause ( IntrospectedTable introspectedTable , XmlElement element , List < Element > values ) { } }

implementation:
element . addElement ( new TextElement ( "select" ) ) ; for ( Element value : values ) { element . addElement ( value ) ; } element . addElement ( new TextElement ( "from dual where not exists" ) ) ; element . addElement ( new TextElement ( "(" ) ) ; element . addElement ( new TextElement ( "select 1 from " + introspectedTable . getFullyQualifiedTableNameAtRuntime ( ) ) ) ; // if example
element . addElement ( XmlElementGeneratorTools . getUpdateByExampleIncludeElement ( introspectedTable ) ) ; element . addElement ( new TextElement ( ")" ) ) ;


signature: public class ByteBucketArray { final T get ( int index ) { } }

implementation:
if ( index >= size ( ) ) { return mDefault ; } // byte bucketIndex = static _ cast < byte > ( index ) > > 4;
byte bucketIndex = ( byte ) ( index >> 4 ) ; T [ ] bucket = ( T [ ] ) mBuckets [ bucketIndex ] ; if ( bucket == null ) { return mDefault ; } T t = bucket [ 0x0f & ( ( byte ) index ) ] ; return t == null ? mDefault : t ;


signature:
public class ResourceTableFactory { /** * Builds an Android framework resource table in the " android " package space . */
public PackageResourceTable newFrameworkResourceTable ( ResourcePath resourcePath ) { } }

implementation: return PerfStatsCollector . getInstance ( ) . measure ( "load legacy framework resources" , ( ) -> { PackageResourceTable resourceTable = new PackageResourceTable ( "android" ) ; if ( resourcePath . getRClass ( ) != null ) { addRClassValues ( resourceTable , resourcePath . getRClass ( ) ) ; addMissingStyleableAttributes ( resourceTable , resourcePath . getRClass ( ) ) ; } if ( resourcePath . getInternalRClass ( ) != null ) { addRClassValues ( resourceTable , resourcePath . getInternalRClass ( ) ) ; addMissingStyleableAttributes ( resourceTable , resourcePath . getInternalRClass ( ) ) ; } parseResourceFiles ( resourcePath , resourceTable ) ; return resourceTable ; } ) ;


signature:
public class ResourceTableFactory { /** * Creates an application resource table which can be constructed with multiple resources paths
 * representing overlayed resource libraries . */
public PackageResourceTable newResourceTable ( String packageName , ResourcePath ... resourcePaths ) { } }

implementation: return PerfStatsCollector . getInstance ( ) . measure ( "load legacy app resources" , ( ) -> { PackageResourceTable resourceTable = new PackageResourceTable ( packageName ) ; for ( ResourcePath resourcePath : resourcePaths ) { if ( resourcePath . getRClass ( ) != null ) { addRClassValues ( resourceTable , resourcePath . getRClass ( ) ) ; } } for ( ResourcePath resourcePath : resourcePaths ) { parseResourceFiles ( resourcePath , resourceTable ) ; } return resourceTable ; } ) ;


signature:
public class ResourceTableFactory { /** * Check the stylable elements . Not for aapt generated R files but for framework R files it is possible to
 * have attributes in the styleable array for which there is no corresponding R . attr field . */
private void addMissingStyleableAttributes ( PackageResourceTable resourceTable , Class < ? > rClass ) { } }

implementation:
for ( Class innerClass : rClass . getClasses ( ) ) { if ( innerClass . getSimpleName ( ) . equals ( "styleable" ) ) { String styleableName = null ; // Current styleable name
int [ ] styleableArray = null ; // Current styleable value array or references
for ( Field field : innerClass . getDeclaredFields ( ) ) { if ( field . getType ( ) . equals ( int [ ] . class ) && Modifier . isStatic ( field . getModifiers ( ) ) ) { styleableName = field . getName ( ) ; try { styleableArray = ( int [ ] ) ( field . get ( null ) ) ; } catch ( IllegalAccessException e ) { throw new RuntimeException ( e ) ; } } else if ( field . getType ( ) . equals ( Integer . TYPE ) && Modifier . isStatic ( field . getModifiers ( ) ) ) { String attributeName = field . getName ( ) . substring ( styleableName . length ( ) + 1 ) ; try { int styleableIndex = field . getInt ( null ) ; int attributeResId = styleableArray [ styleableIndex ] ; resourceTable . addResource ( attributeResId , "attr" , attributeName ) ; } catch ( IllegalAccessException e ) { throw new RuntimeException ( e ) ; } } } } }


signature:
public class ShadowSettings { /** * Sets the value of the { @ link Settings . System # AIRPLANE _ MODE _ ON } setting .
 * @ param isAirplaneMode new status for airplane mode */
public static void setAirplaneMode ( boolean isAirplaneMode ) { } }

implementation: Settings . Global . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Global . AIRPLANE_MODE_ON , isAirplaneMode ? 1 : 0 ) ; Settings . System . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . System . AIRPLANE_MODE_ON , isAirplaneMode ? 1 : 0 ) ;


signature:
public class ShadowSettings { /** * Non - Android accessor that allows the value of the WIFI _ ON setting to be set .
 * @ param isOn new status for wifi mode */
public static void setWifiOn ( boolean isOn ) { } }

implementation: Settings . Global . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Global . WIFI_ON , isOn ? 1 : 0 ) ; Settings . System . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . System . WIFI_ON , isOn ? 1 : 0 ) ;


signature:
public class ShadowSettings { /** * Sets the value of the { @ link Settings . System # TIME _ 12_24 } setting .
 * @ param use24HourTimeFormat new status for the time setting */
public static void set24HourTimeFormat ( boolean use24HourTimeFormat ) { } }

implementation: Settings . System . putString ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . System . TIME_12_24 , use24HourTimeFormat ? "24" : "12" ) ;


signature:
public class ShadowSettings { /** * Sets the value of the { @ link Settings . Global # ADB _ ENABLED } setting or { @ link
 * Settings . Secure # ADB _ ENABLED } depending on API level .
 * @ param adbEnabled new value for whether adb is enabled */
public static void setAdbEnabled ( boolean adbEnabled ) { } }

implementation:
// This setting moved from Secure to Global in JELLY _ BEAN _ MR1
if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . JELLY_BEAN_MR1 ) { Settings . Global . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Global . ADB_ENABLED , adbEnabled ? 1 : 0 ) ; } // Support all clients by always setting the Secure version of the setting
Settings . Secure . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Secure . ADB_ENABLED , adbEnabled ? 1 : 0 ) ;


signature:
public class ShadowSettings { /** * Sets the value of the { @ link Settings . Global # INSTALL _ NON _ MARKET _ APPS } setting or { @ link
 * Settings . Secure # INSTALL _ NON _ MARKET _ APPS } depending on API level .
 * @ param installNonMarketApps new value for whether non - market apps are allowed to be installed */
public static void setInstallNonMarketApps ( boolean installNonMarketApps ) { } }

implementation:
// This setting moved from Secure to Global in JELLY _ BEAN _ MR1 and then moved it back to Global
// in LOLLIPOP . Support all clients by always setting this field on all versions > =
// JELLY _ BEAN _ MR1.
if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . JELLY_BEAN_MR1 ) { Settings . Global . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Global . INSTALL_NON_MARKET_APPS , installNonMarketApps ? 1 : 0 ) ; } // Always set the Secure version of the setting
Settings . Secure . putInt ( RuntimeEnvironment . application . getContentResolver ( ) , Settings . Secure . INSTALL_NON_MARKET_APPS , installNonMarketApps ? 1 : 0 ) ;


signature:
public class MavenDependencyResolver { /** * Get an array of local artifact URLs for the given dependencies . The order of the URLs is guaranteed to be the
 * same as the input order of dependencies , i . e . , urls [ i ] is the local artifact URL for dependencies [ i ] . */
@ SuppressWarnings ( "NewApi" ) public URL [ ] getLocalArtifactUrls ( DependencyJar ... dependencies ) { } }

implementation: DependenciesTask dependenciesTask = createDependenciesTask ( ) ; configureMaven ( dependenciesTask ) ; RemoteRepository remoteRepository = new RemoteRepository ( ) ; remoteRepository . setUrl ( repositoryUrl ) ; remoteRepository . setId ( repositoryId ) ; if ( repositoryUserName != null || repositoryPassword != null ) { Authentication authentication = new Authentication ( ) ; authentication . setUserName ( repositoryUserName ) ; authentication . setPassword ( repositoryPassword ) ; remoteRepository . addAuthentication ( authentication ) ; } dependenciesTask . addConfiguredRemoteRepository ( remoteRepository ) ; final Project project = new Project ( ) ; dependenciesTask . setProject ( project ) ; for ( DependencyJar dependencyJar : dependencies ) { Dependency dependency = new Dependency ( ) ; dependency . setArtifactId ( dependencyJar . getArtifactId ( ) ) ; dependency . setGroupId ( dependencyJar . getGroupId ( ) ) ; dependency . setType ( dependencyJar . getType ( ) ) ; dependency . setVersion ( dependencyJar . getVersion ( ) ) ; if ( dependencyJar . getClassifier ( ) != null ) { dependency . setClassifier ( dependencyJar . getClassifier ( ) ) ; } dependenciesTask . addDependency ( dependency ) ; } whileLocked ( dependenciesTask :: execute ) ; @ SuppressWarnings ( "unchecked" ) Hashtable < String , String > artifacts = project . getProperties ( ) ; URL [ ] urls = new URL [ dependencies . length ] ; for ( int i = 0 ; i < urls . length ; i ++ ) { try { urls [ i ] = Paths . get ( artifacts . get ( key ( dependencies [ i ] ) ) ) . toUri ( ) . toURL ( ) ; } catch ( MalformedURLException e ) { throw new RuntimeException ( e ) ; } } return urls ;


signature:
public class Qualifiers { /** * If the Config already has a version qualifier , do nothing . Otherwise , add a version
 * qualifier for the target api level ( which comes from the manifest or Config . sdk ( ) ) .
 * @ deprecated Figure something else out . */
@ Deprecated public static String addPlatformVersion ( String qualifiers , int apiLevel ) { } }

implementation: int versionQualifierApiLevel = Qualifiers . getPlatformVersion ( qualifiers ) ; if ( versionQualifierApiLevel == - 1 ) { if ( qualifiers . length ( ) > 0 ) { qualifiers += "-" ; } qualifiers += "v" + apiLevel ; } return qualifiers ;


signature:
public class Qualifiers { /** * If the Config already has a ` sw ` qualifier , do nothing . Otherwise , add a ` sw `
 * qualifier for the given width .
 * @ deprecated Use { @ link android . content . res . Configuration # smallestScreenWidthDp } instead . */
@ Deprecated public static String addSmallestScreenWidth ( String qualifiers , int smallestScreenWidth ) { } }

implementation: int qualifiersSmallestScreenWidth = Qualifiers . getSmallestScreenWidth ( qualifiers ) ; if ( qualifiersSmallestScreenWidth == - 1 ) { if ( qualifiers . length ( ) > 0 ) { qualifiers += "-" ; } qualifiers += "sw" + smallestScreenWidth + "dp" ; } return qualifiers ;


signature:
public class ClassInstrumentor { /** * Generates code like this :
 * ` ` ` java
 * protected void $ $ robo $ init ( ) {
 * if ( _ _ robo _ data _ _ = = null ) {
 * _ _ robo _ data _ _ = RobolectricInternals . initializing ( this ) ; */
private void addRoboInitMethod ( MutableClass mutableClass ) { } }

implementation:
MethodNode initMethodNode = new MethodNode ( Opcodes . ACC_PROTECTED , ROBO_INIT_METHOD_NAME , "()V" , null , null ) ; RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter ( initMethodNode ) ; Label alreadyInitialized = new Label ( ) ; generator . loadThis ( ) ; // this
generator . getField ( mutableClass . classType , ShadowConstants . CLASS_HANDLER_DATA_FIELD_NAME , OBJECT_TYPE ) ; // contents of _ _ robo _ data _ _
generator . ifNonNull ( alreadyInitialized ) ; generator . loadThis ( ) ; // this
generator . loadThis ( ) ; // this , this
writeCallToInitializing ( mutableClass , generator ) ; // this , _ _ robo _ data _ _
generator . putField ( mutableClass . classType , ShadowConstants . CLASS_HANDLER_DATA_FIELD_NAME , OBJECT_TYPE ) ; generator . mark ( alreadyInitialized ) ; generator . returnValue ( ) ; mutableClass . addMethod ( initMethodNode ) ;


signature:
public class ClassInstrumentor { /** * Constructors are instrumented as follows :
 * # Code other than a call to the superclass constructor is moved to a new method named
 * ` _ _ constructor _ _ ` with the same signature .
 * # The constructor is modified to call { @ link ClassHandler # initializing ( Object ) } ( or
 * { @ link ClassHandler # getShadowCreator ( Class ) } for ` invokedynamic ` JVMs ) .
 * # The constructor is modified to then call
 * { @ link ClassHandler # methodInvoked ( String , boolean , Class ) } ( or
 * { @ link ClassHandler # findShadowMethodHandle ( Class , String , MethodType , boolean ) } for
 * ` invokedynamic ` JVMs ) with the method name ` _ _ constructor _ _ ` and the same parameter types .
 * Note that most code in the constructor will not be executed unless the { @ link ClassHandler }
 * arranges for it to happen .
 * Given a constructor like this :
 * ` ` ` java
 * public ThisClass ( String name , int size ) {
 * super ( name , someStaticMethod ( ) ) ;
 * this . size = size ;
 * . . . generates code like this :
 * ` ` ` java
 * private $ $ robo $ $ _ _ constructor _ _ ( String name , int size ) {
 * this . size = size ;
 * private _ _ constructor _ _ ( String name , int size ) {
 * Plan plan = RobolectricInternals . methodInvoked (
 * " pkg / ThisClass / _ _ constructor _ _ ( Ljava / lang / String ; I ) V " , true , ThisClass . class ) ;
 * if ( plan ! = null ) {
 * try {
 * plan . run ( this , new Object [ ] { name , size } ) ;
 * } catch ( Throwable t ) {
 * throw RobolectricInternals . cleanStackTrace ( t ) ;
 * } else {
 * $ $ robo $ $ _ _ constructor _ _ ( name , size ) ;
 * public ThisClass ( String name , int size ) {
 * super ( name , someStaticMethod ( ) ) ;
 * $ $ robo $ init ( ) ;
 * @ param method the constructor to instrument */
private void instrumentConstructor ( MutableClass mutableClass , MethodNode method ) { } }

implementation:
makeMethodPrivate ( method ) ; if ( mutableClass . containsStubs ) { // method . instructions just throws a ` stub ! ` exception , replace it with something anodyne . . .
method . instructions . clear ( ) ; RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter ( method ) ; generator . loadThis ( ) ; generator . visitMethodInsn ( Opcodes . INVOKESPECIAL , mutableClass . classNode . superName , "<init>" , "()V" , false ) ; generator . returnValue ( ) ; generator . endMethod ( ) ; } InsnList callSuper = extractCallToSuperConstructor ( mutableClass , method ) ; method . name = directMethodName ( mutableClass , ShadowConstants . CONSTRUCTOR_METHOD_NAME ) ; mutableClass . addMethod ( redirectorMethod ( mutableClass , method , ShadowConstants . CONSTRUCTOR_METHOD_NAME ) ) ; String [ ] exceptions = exceptionArray ( method ) ; MethodNode initMethodNode = new MethodNode ( method . access , "<init>" , method . desc , method . signature , exceptions ) ; makeMethodPublic ( initMethodNode ) ; RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter ( initMethodNode ) ; initMethodNode . instructions = callSuper ; generator . loadThis ( ) ; generator . invokeVirtual ( mutableClass . classType , new Method ( ROBO_INIT_METHOD_NAME , "()V" ) ) ; generateClassHandlerCall ( mutableClass , method , ShadowConstants . CONSTRUCTOR_METHOD_NAME , generator ) ; generator . endMethod ( ) ; mutableClass . addMethod ( initMethodNode ) ;


signature:
public class ClassInstrumentor { /** * # Rename the method from ` methodName ` to ` $ $ robo $ $ methodName ` .
 * # Make it private so we can invoke it directly without subclass overrides taking precedence .
 * # Remove ` final ` modifiers , if present .
 * # Create a delegator method named ` methodName ` which delegates to the { @ link ClassHandler } . */
protected void instrumentNormalMethod ( MutableClass mutableClass , MethodNode method ) { } }

implementation:
// if not abstract , set a final modifier
if ( ( method . access & Opcodes . ACC_ABSTRACT ) == 0 ) { method . access = method . access | Opcodes . ACC_FINAL ; } if ( ( method . access & Opcodes . ACC_NATIVE ) != 0 ) { instrumentNativeMethod ( mutableClass , method ) ; } // todo figure out
String originalName = method . name ; method . name = directMethodName ( mutableClass , originalName ) ; MethodNode delegatorMethodNode = new MethodNode ( method . access , originalName , method . desc , method . signature , exceptionArray ( method ) ) ; delegatorMethodNode . visibleAnnotations = method . visibleAnnotations ; delegatorMethodNode . access &= ~ ( Opcodes . ACC_NATIVE | Opcodes . ACC_ABSTRACT | Opcodes . ACC_FINAL ) ; makeMethodPrivate ( method ) ; RobolectricGeneratorAdapter generator = new RobolectricGeneratorAdapter ( delegatorMethodNode ) ; generateClassHandlerCall ( mutableClass , method , originalName , generator ) ; generator . endMethod ( ) ; mutableClass . addMethod ( delegatorMethodNode ) ;