Gradle Plugin for MyBatis Generator

因为项目原因,最近又重新看了一下MyBatis,发现MyBatis只有Ant和Maven的Generator,没有Gradle的插件。而现在Gradle已经越来越流行,没有Gradle插件怎么行。
编写Gradle插件,可以从头自己实现,也可以调用现有的Ant Task。MyBatis已经有Ant的Generator了,所以我决定不重造轮子,调用Ant的Task就行了。

定义插件Task的类型

编写插件就是为了重用一些Task,比如Gradle的Java插件,就提供了编译、测试以及打包等Task,这样在构建脚本里使用:

1
apply: 'java'

就可以使用这些Task。所以我们自定义插件,就难免要为插件定义Task。Gradle中的Task也是有类型的,比如Copy的Task。自定义Task也可以继承已经有的Task,但是我们这里要使用的Task是Ant提供的,所以我们需要继承ConventionTask。

Task的定义
1
2
3
4
5
6
7
class MyBatisGeneratorTask extends ConventionTask {
    //Define some properties
    @TaskAction
    void executeCargoAction() {
  //Implement the task action
    }
}

申明了Task之后,就需要实现Task的Action了,就是该Task都做哪些事情。我们这里要调用MyBatis的Ant任务,所以需要使用IsolatedAntBuilder。代码如下:

Task的Action实现
1
2
3
4
5
6
7
8
9
services.get(IsolatedAntBuilder).withClasspath(getMyBatisGeneratorClasspath()).execute {
       ant.taskdef(name: 'mbgenerator',
                       classname: 'org.mybatis.generator.ant.GeneratorAntTask')

       ant.properties['generated.source.dir'] = getTargetDir()
       ant.mbgenerator(overwrite: getOverwrite(),
                          configfile: getConfigFile(),
                          verbose: getVerbose()) {}
}

跟Ant里一样,要使用自定义的Ant任务,就必须先通过Ant的Taskdef定义一个Task,之后才能在Ant脚本里使用。同样在Gradle里也通过ant.taskdef来定义新的Ant任务。要定义Task,我们就需要制定从哪个classpath下去加载指定的类名org.mybatis.generator.ant.GeneratorAntTask。这里我们通过getMyBatisGeneratorClasspath()获得,这就需要我们在使用该Gradle Task的时候讲classpath传到Task里去,所以我们就需要定义Task的属性了。同时,大家还应该注意到这里不止一个getMyBatisGeneratorClasspath()方法,还有其他的Get方法,这些Get方法都是从Task的属性取值。我们的Task属性定义如下:

Task的属性
1
2
3
4
5
def overwrite
def configFile
def verbose
def targetDir
FileCollection myBatisGeneratorClasspath

编写Plugin

有了Task类型之后,我们就可以编写Plugin了。自定义Plugin需要实现Plugin接口:

Plugin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class MyBatisGeneratorPlugin implements Plugin<ProjectInternal> {
    @Override
    void apply(ProjectInternal project) {
        project.logger.info "Configuring MyBatis Generator for project: $project.name"
        MyBatisGeneratorTask task = project.tasks.create("mbGenerator", MyBatisGeneratorTask);
        project.configurations.create('mybatis').with {
            description = 'The MyBatis Generator to be used for this project.'
        }
        project.extensions.create("mybatis", MyBatisGeneratorPluginExtension)

        task.conventionMapping.with {
            myBatisGeneratorClasspath = {
                def config = project.configurations['mybatis']
                if (config.dependencies.empty) {
                    project.dependencies {
                        mybatis('org.mybatis.generator:mybatis-generator-core:1.3.2')
                    }
                }
                config
            }
            overwrite = { project.mybatis.overwrite }
            configFile = { project.mybatis.configFile }
            verbose = { project.mybatis.verbose }
            targetDir = { project.mybatis.targetDir }
        }

    }
}

在这里我们通过MyBatisGeneratorTask task = project.tasks.create(“mbGenerator”, MyBatisGeneratorTask);创建一个Task并给该Task指定相应的属性。

插件的配置

要编写插件,就难免需要在Gradle里配置该插件。在Gradle的插件里,通常都提供默认配置值,但是有时在Gradle构建脚本里也需要让用户自定义。在Gradle里使用extension objects方法,通过Project的ExtensionContainer对象,把构建脚本里的配置信息传到插件里。Extension很简单,就是简单的Groovy对象:

Extension的定义
1
2
3
4
5
6
7
@ToString(includeNames = true)
class MyBatisGeneratorPluginExtension {
    def overwrite = true
    def configFile = "generatorConfig.xml"
    def verbose = false
    def targetDir = "."
}

接下来就是在插件里使用这个Extension:

Extension的使用
1
project.extensions.create("mybatis", MyBatisGeneratorPluginExtension)

这里就会把构建脚本里的mybatis的配置,合并到我们提供的Extension里去,比如在构建脚本里提供如下的配置:

配置插件
1
2
3
mybatis{
    configFile = '../generatorConfig.xml'
}

就会覆盖默认的configFile配置,默认会从当前目录里去找generatorConfig.xml的文件,但是经过我们配置之后,就会从上级目录去找该文件。

Summary

至此,Gradle的MyBatis插件编写完毕,下面一个问题就是如何在项目中使用。该插件已经上传到Github:https://github.com/reverocean/MyBatisGenerator

Comments

Comments