使用默认生成类策略
项目中采用了jOOQ作为ORM框架,并使用jOOQ codegen生成Table,Record和PO。
codegen使用说明请见这里。codegen的gradle配置请见这里。
表结构:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_name` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
gradle配置:
import groovy.xml.MarkupBuilder
import org.jooq.util.GenerationTool
import javax.xml.bind.JAXB
buildscript {
ext {
springBootVersion = '1.5.4.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath('mysql:mysql-connector-java:5.1.39')
classpath('org.jooq:jooq-codegen:3.9.1')
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'war'
version = '1.0'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
configurations {
providedRuntime
}
dependencies {
compile('org.springframework.boot:spring-boot-starter-jooq')
compile('mysql:mysql-connector-java:5.1.39')
compile('com.zaxxer:HikariCP:2.6.1')
compileOnly('org.jooq:jooq-codegen:3.9.1')
}
task jooq_code_generate(type: Task) {
// Use your favourite XML builder to construct the code generation configuration file
def writer = new StringWriter()
def xml = new MarkupBuilder(writer)
.configuration('xmlns': 'http://www.jooq.org/xsd/jooq-codegen-3.9.0.xsd') {
jdbc() {
driver('com.mysql.jdbc.Driver')
url('jdbc:mysql://${IP}:${PORT}?characterEncoding=UTF-8&allowMultiQueries=true')
user('${username}')
password('${passwd}')
}
generator() {
database() {
name('org.jooq.util.mysql.MySQLDatabase')
inputSchema('${schema}')
includes("user")
// excludes("schema_version")
}
generate([:]) {
pojos true
// daos true
}
target() {
packageName('com.landas.temp')
directory('src/main/java')
encoding("UTF-8")
}
}
}
// Run the code generator
doLast {
GenerationTool.generate(
JAXB.unmarshal(new StringReader(writer.toString()),
org.jooq.util.jaxb.Configuration.class)
)
}
}
此时运行task,生成的po如下:
public class User implements Serializable {
private static final long serialVersionUID = -1585262004;
private Integer id;
private String userName;
// omitted...
}
可见codegen将数据库中的下划线自动转换为了驼峰命名。
因为要兼容老接口,必须将userName改为user_name格式。
修改默认策略
打开上面gradle配置中的xmlns定义URL,发现Generator中有strategy配置项:
<complexType name="Generator">
<all>
<element name="name" type="string" default="org.jooq.util.DefaultGenerator" minOccurs="0" maxOccurs="1"/>
<element name="strategy" type="tns:Strategy" minOccurs="0" maxOccurs="1"/>
<element name="database" type="tns:Database" minOccurs="1" maxOccurs="1"/>
<element name="generate" type="tns:Generate" minOccurs="0" maxOccurs="1"/>
<element name="target" type="tns:Target" minOccurs="0" maxOccurs="1"/>
</all>
</complexType>
<complexType name="Strategy">
<choice>
<element name="name" type="string" minOccurs="0" maxOccurs="1" default="org.jooq.util.DefaultGeneratorStrategy"/>
<element name="matchers" type="tns:Matchers" minOccurs="0" maxOccurs="1"/>
</choice>
</complexType>
查询jOOQ codegen文档,发现确实可以在generator中配置策略。按照文档教程,自定义了策略类AsInDatabaseStratege,添加到generator中,修改后的gradle文件如下:
// omitted ...
generator() {
database() {
name('org.jooq.util.mysql.MySQLDatabase')
inputSchema('${schema}')
includes("user")
// excludes("schema_version")
}
strategy() {
name('com.landas.AsInDatabaseStrategy')
}
generate([:]) {
pojos true
// daos true
}
target() {
packageName('com.landas.temp')
directory('src/main/java')
encoding("UTF-8")
}
}
// omitted ...
AsInDatabaseStratege类如下,注意几个重写的方法getJavaMemberName/getJavaSetterName等:
import org.jooq.util.DefaultGeneratorStrategy;
import org.jooq.util.Definition;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
/**
* Created by Landas on 2017/10/17.
*/
public class AsInDatabaseStrategy extends DefaultGeneratorStrategy {
/**
* Override this to specifiy what identifiers in Java should look like.
* This will just take the identifier as defined in the database.
*/
@Override
public String getJavaIdentifier(Definition definition) {
return definition.getOutputName();
}
/**
* Override these to specify what a setter in Java should look like. Setters
* are used in TableRecords, UDTRecords, and POJOs. This example will name
* setters "set[NAME_IN_DATABASE]"
*/
@Override
public String getJavaSetterName(Definition definition, Mode mode) {
String name = definition.getOutputName();
return "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
}
/**
* Just like setters...
*/
@Override
public String getJavaGetterName(Definition definition, Mode mode) {
String name = definition.getOutputName();
return "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
}
/**
* Override this method to define what a Java method generated from a database
* Definition should look like. This is used mostly for convenience methods
* when calling stored procedures and functions. This example shows how to
* set a prefix to a CamelCase version of your procedure
*/
@Override
public String getJavaMethodName(Definition definition, Mode mode) {
return "call" + org.jooq.tools.StringUtils.toCamelCase(definition.getOutputName());
}
/**
* Override this method to define how your Java classes and Java files should
* be named. This example applies no custom setting and uses CamelCase versions
* instead
*/
@Override
public String getJavaClassName(Definition definition, Mode mode) {
return super.getJavaClassName(definition, mode);
}
/**
* Override this method to re-define the package names of your generated
* artefacts.
*/
@Override
public String getJavaPackageName(Definition definition, Mode mode) {
return super.getJavaPackageName(definition, mode);
}
/**
* Override this method to define how Java members should be named. This is
* used for POJOs and method arguments
*/
@Override
public String getJavaMemberName(Definition definition, Mode mode) {
return definition.getOutputName();
}
/**
* Override this method to define the base class for those artefacts that
* allow for custom base classes
*/
@Override
public String getJavaClassExtends(Definition definition, Mode mode) {
return Object.class.getName();
}
/**
* Override this method to define the interfaces to be implemented by those
* artefacts that allow for custom interface implementation
*/
@Override
public List<String> getJavaClassImplements(Definition definition, Mode mode) {
return Arrays.asList(Serializable.class.getName(), Cloneable.class.getName());
}
/**
* Override this method to define the suffix to apply to routines when
* they are overloaded.
*
* Use this to resolve compile-time conflicts in generated source code, in
* case you make heavy use of procedure overloading
*/
@Override
public String getOverloadSuffix(Definition definition, Mode mode, String overloadIndex) {
return "_OverloadIndex_" + overloadIndex;
}
}
注意,这个类直接放在项目中gradle任务运行时是引用不到的,会报找不到类的异常:
Execution failed for task ':jooq_code_generate'.
> java.lang.ClassNotFoundException: com.landas.AsInDatabaseStrategy
为了让任务正常运行,需要在项目中新建buildSrc目录,将自定义的类放到buildSrc的src目录下,gradle能自动引用到此目录下的所有类(详情请查询gradle手册)。此时项目结构如下:
buildSrc中的gradle配置如下:
apply plugin: 'groovy'
version=1.0
repositories {
mavenCentral()
}
dependencies {
compile('org.jooq:jooq-codegen:3.9.1')
compile gradleApi()
compile localGroovy()
}
此时,重新运行 jooq_code_generate 任务,得到期望的结果:
public class User implements Serializable {
private Integer id;
private String user_name;
// omitted ...
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUser_name() {
return this.user_name;
}
public void setUser_name(String user_name) {
this.user_name = user_name;
}
// omitted ...
}