网上GreenDao相关的资料不是特别多,除了官方文档几乎没有特别好的资料。自己整理了一份,以备不时之需。
从源码上来分,GreenDao大体可以分成两个项目,DaoCore和DaoGenerator。
DaoGenerator部分:
FreeMarker
DaoGenerator使用FreeMarker根据指定的schema生成代码。
为了能够更好的介绍DaoGenerator的代码,有必要先简单介绍一下FreeMarker的基本功能,
一个基本的FreeMarker工程一般有这三个步骤组成。
1.声明一个configration,用来处理生成代码的逻辑
Configuration config =
new Configuration();
config.setClassForTemplateLoading(this.getClass(),
"/");
config.setObjectWrapper(new
DefaultObjectWrapper());
指定模版文件地址的方式有三种,
public void setClassForTemplateLoading(Class clazz, String pathPrefix);
public void setDirectoryForTemplateLoading(File dir) throws IOException;
public void setServletContextForTemplateLoading(Object servletContext, String path);
分别基于类路径、文件系统以及Servlet Context
2.生成ftl文件,用来作为生成代码的模版
Template temp = config.getTemplate("test.ftl”);
<html>
<head>
<title>Welcome!</title> </head>
<body>
<h1>Welcome ${user}!</h1>
<p>Our latest product:
<a href="${latestProduct.url}">${latestProduct.name}</a>!
</body>
</html>
这是一个简单的ftl模版的样子,其中${X}表示要用替换对象X进行替换。
3.通过config读取指定的ftl,生成template,进而结合模版,替换对象,输出流,生成最终的文件
Map root = this.getRoot();
Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);
out.flush();
这里的替换对象可以是Map的,也可以是一个普通的bean。
DaoGenerator:
下面切入正题开始看DaoGenerator的代码吧
包路径de.greenrobot.daogenerator 下面有如下几个类:
ContentProvider,
DaoGenerator,
DaoUtil,
Entity,
Index,
Property,
PropertyOrderList,
PropertyType,
Query,
QueryParam,
Schema,
ToMany,
ToOne,
使用顺序:
Schema作为一次完整的活动,它指定了生成代码的包名,其内部一般会有多个Entity,一个Entity对应数据库一张表,Entity下的Property,每个Property对应数据库中一个列。DaoGenerator作为一个入口,通过他的generateAll()方法来触发代码生成。
一般使用的顺序是这样的,先new一个schema,指定好生成代码包路径,然后通过Schema.addEntity(“表名”)得到一个Entity,然后再通过Entity.addXXProperty(“列名”)将指定的property添加到Entity(XX表示列的类型,比如int,String,等等)。
关系指定好之后通过DaoGenerator.generateAll(schema,srcOutputPath),触发根据schema中的关系和参数在数据库中建表,并在指定位置生成相应的实体bean和DAOs。
顺着使用时候的思路,我们来看一下源码里有什么值得我们借鉴的地方吧:
1.在Property的构造部分,由于property参数较多,这里他采用了Builder模式[Gamma95,p97],不直接生成想要的对象,而是让使用者利用必要的参数调用构造器(或者工厂模式),得到一个builder对象,然后使用者在builder对象上调用类似setter的方法,来设置每个可选的相关参数。 最后使用者调用build方法生成不可变的对象。这个builder是他构建的类的静态成员类,下面是他的实现:
public class Property {
public static class PropertyBuilder {
private final Property property;
public PropertyBuilder(Schema schema, Entity entity, PropertyType propertyType, String propertyName) {
property = new Property(schema, entity, propertyType, propertyName);
}
public PropertyBuilder columnName(String columnName) {
property.columnName = columnName;
return this;
}
public PropertyBuilder columnType(String columnType) {
property.columnType = columnType;
return this;
}
.
.
.
.
.
public Property getProperty() { return property; }
}
.
.
}
使用起来是这个样子的:
public PropertyBuilder addProperty(PropertyType propertyType, String propertyName) {
if (!propertyNames.add(propertyName)) {
throw new RuntimeException("Property already defined: " + propertyName);
}
PropertyBuilder builder = new Property.PropertyBuilder(schema, this, propertyType, propertyName);
properties.add(builder.getProperty());
return builder;
}
public PropertyBuilder addIdProperty() {
PropertyBuilder builder = addLongProperty("id");
builder.columnName("_id").primaryKey();
return builder;
}
注意这里类似setter的方法(columnName,columnType,等等)返回的都是builder本身,这样就可以把调用链起来。