關于上篇說到的數據庫更新問題,我正在找國外大牛的二次封裝的github代碼。找到會貼出來。
咱們這篇,小小地分析下greendao-generator的源碼,和大家一起了解下,代碼的生成。
咱們寫的java項目代碼很簡單,就是個初始化Schema——>添加Entity
——>生成的過程。
- Schema
我們看下我們寫的代碼
~~~
Schema schema = new Schema(2,"gl.com.greendaodemo");
~~~
很簡單,就是版本號+生成代碼包名。
我們看下Schema的部分源碼。
~~~
private final int version;
private final String defaultJavaPackage;
private String defaultJavaPackageDao;
private String defaultJavaPackageTest;
private final List<Entity> entities;
private Map<PropertyType, String> propertyToDbType;
private Map<PropertyType, String> propertyToJavaTypeNotNull;
private Map<PropertyType, String> propertyToJavaTypeNullable;
private boolean hasKeepSectionsByDefault;
private boolean useActiveEntitiesByDefault;
public Schema(int version, String defaultJavaPackage) {
this.version = version;
this.defaultJavaPackage = defaultJavaPackage;
this.entities = new ArrayList<Entity>();
initTypeMappings();
}
~~~
看得出,構造函數就是初始化了數據庫版本、包名、實體list以及屬性類型(initTypeMappings()來完成屬性類型初始化),下面貼出這個函數的部分代碼
~~~
propertyToDbType = new HashMap<PropertyType, String>();
propertyToDbType.put(PropertyType.Boolean, "INTEGER");
propertyToDbType.put(PropertyType.Byte, "INTEGER");
propertyToDbType.put(PropertyType.Short, "INTEGER");
propertyToDbType.put(PropertyType.Int, "INTEGER");
propertyToDbType.put(PropertyType.Long, "INTEGER");
propertyToDbType.put(PropertyType.Float, "REAL");
propertyToDbType.put(PropertyType.Double, "REAL");
propertyToDbType.put(PropertyType.String, "TEXT");
propertyToDbType.put(PropertyType.ByteArray, "BLOB");
propertyToDbType.put(PropertyType.Date, "INTEGER");
~~~
Schema的初始化看完了,接下來我們看下如何添加實體
- Entity以及addEntity
~~~
Entity people = schema.addEntity("People");
people.addStringProperty("name").primaryKey(); //名字
people.addIntProperty("age"); //年齡
~~~
上面是添加一個實體的過程,我們瞅瞅addEntity();函數
~~~
public Entity addEntity(String className) {
Entity entity = new Entity(this, className);
entities.add(entity);
return entity;
}
~~~
嗯,簡單 ,就是給list添加了一個對象。。。那么,給實體添加約束的源碼又是什么呢?我們以addIdProperty()為例。
~~~
public PropertyBuilder addIdProperty() {
PropertyBuilder builder = addLongProperty("id");
builder.columnName("_id").primaryKey();
return builder;
}
~~~
可以看到,這里直接將給了個_id的列并作為主鍵存在。上面有用到PropertyBuilder這個類,這個是干什么的?

,偶,這個類就是給數據庫中的字段設置約束的。看到,有自增、非空、主鍵等等。
~~~
person.addStringProperty("name")
~~~
我們看看如何給字段指定類型。上面 的哪一行代碼 最終會調用 下面這個構造函數。可以看到,這里就有了字段類型了,那么字段類型又有哪些呢,還記得我們在初始化Schema的時候的代碼么,沒錯,就是那些。但是,光那些是不夠用的,greendao還支持我們自定義。請移步[官方介紹](http://greendao-orm.com/documentation/custom-types/)
~~~
public Property(Schema schema, Entity entity, PropertyType propertyType, String propertyName) {
this.schema = schema;
this.entity = entity;
this.propertyName = propertyName;
this.propertyType = propertyType;
}
~~~
接下來便是重頭戲,代碼生成部分
- 代碼生成
-
~~~
new DaoGenerator().generateAll(schema, "/Users/mac/Desktop/GLandroidstudy/AS/greendaodemo/src/main/java-gen");
~~~
我們看看DaoGenerator的構造函數
~~~
public DaoGenerator() throws IOException {
System.out.println("greenDAO Generator");
System.out.println("Copyright 2011-2015 Markus Junginger, greenrobot.de. Licensed under GPL V3.");
System.out.println("This program comes with ABSOLUTELY NO WARRANTY");
patternKeepIncludes = compilePattern("INCLUDES");
patternKeepFields = compilePattern("FIELDS");
patternKeepMethods = compilePattern("METHODS");
Configuration config = new Configuration();
config.setClassForTemplateLoading(this.getClass(), "/");
config.setObjectWrapper(new DefaultObjectWrapper());
templateDao = config.getTemplate("dao.ftl");
templateDaoMaster = config.getTemplate("dao-master.ftl");
templateDaoSession = config.getTemplate("dao-session.ftl");
templateEntity = config.getTemplate("entity.ftl");
templateDaoUnitTest = config.getTemplate("dao-unit-test.ftl");
templateContentProvider = config.getTemplate("content-provider.ftl");
}
~~~
那個.ftl文件是什么呢?.ftl是Freemarker文件的后綴名,是個模版語言引擎。關于Freemarker更多介紹,自行百度。我們以entity.ftl為例,簡單介紹幾行。
~~~
public class ${entity.className}<#if
entity.superclass?has_content> extends ${entity.superclass} </#if><#if
entity.interfacesToImplement?has_content> implements <#list entity.interfacesToImplement
as ifc>${ifc}<#if ifc_has_next>, </#if></#list></#if> {
<#list entity.properties as property>
<#if property.notNull && complexTypes?seq_contains(property.propertyType)>
/** Not-null value. */
</#if>
<#if property.codeBeforeField ??>
${property.codeBeforeField}
</#if>
private ${property.javaTypeInEntity} ${property.propertyName};
</#list>
~~~
上面的結果就是
~~~
private class classname (extends supperclass )(implements interface){
private type property;
...
}
~~~
就是輸出類似上面的東西,其實語法很簡單,就是根據傳進來的entity實體,根據entity實體的內容來講${}部分用對應的東西替代,最后就輸出成我們的文件了。好,就這么多把,我們再來看下generateAll()的代碼。
~~~
public void generateAll(Schema schema, String outDir, String outDirEntity, String outDirTest) throws Exception {
long start = System.currentTimeMillis();
File outDirFile = toFileForceExists(outDir);
File outDirEntityFile = outDirEntity != null? toFileForceExists(outDirEntity): outDirFile;
File outDirTestFile = outDirTest != null ? toFileForceExists(outDirTest) : null;
schema.init2ndPass();
schema.init3rdPass();
System.out.println("Processing schema version " + schema.getVersion() + "...");
List<Entity> entities = schema.getEntities();
for (Entity entity : entities) {
generate(templateDao, outDirFile, entity.getJavaPackageDao(), entity.getClassNameDao(), schema, entity);
if (!entity.isProtobuf() && !entity.isSkipGeneration()) {
generate(templateEntity, outDirEntityFile, entity.getJavaPackage(), entity.getClassName(), schema, entity);
}
if (outDirTestFile != null && !entity.isSkipGenerationTest()) {
String javaPackageTest = entity.getJavaPackageTest();
String classNameTest = entity.getClassNameTest();
File javaFilename = toJavaFilename(outDirTestFile, javaPackageTest, classNameTest);
if (!javaFilename.exists()) {
generate(templateDaoUnitTest, outDirTestFile, javaPackageTest, classNameTest, schema, entity);
} else {
System.out.println("Skipped " + javaFilename.getCanonicalPath());
}
}
for (ContentProvider contentProvider : entity.getContentProviders()) {
Map<String, Object> additionalObjectsForTemplate = new HashMap<String, Object>();
additionalObjectsForTemplate.put("contentProvider", contentProvider);
generate(templateContentProvider, outDirFile, entity.getJavaPackage(), entity.getClassName()
+ "ContentProvider", schema, entity, additionalObjectsForTemplate);
}
}
generate(templateDaoMaster, outDirFile, schema.getDefaultJavaPackageDao(), "DaoMaster", schema, null);
generate(templateDaoSession, outDirFile, schema.getDefaultJavaPackageDao(), "DaoSession", schema, null);
long time = System.currentTimeMillis() - start;
System.out.println("Processed " + entities.size() + " entities in " + time + "ms");
}
~~~
最后都會調用上面的一段代碼,上面的代碼在做什么呢。顯示創建幾個文件夾,然后遍歷List< Entity>,輸出內容的
~~~
generate(templateEntity, outDirEntityFile, entity.getJavaPackage(), entity.getClassName(), schema, entity);
~~~
就是根據傳進來的末班,包名,類名,schema,實體,替換掉模板中對應的,輸出。關于具體輸出的源碼,實在是太長了,童鞋們自己看吧。
- 前言
- Android四大圖片緩存框架之-Fresco(一)
- Android四大圖片緩存框架之-Fresco之initialize(二)
- Android 四大緩存框架之-Universal-Image-Loader
- Android四大圖片緩存框架之-Picasso和Glide
- Android ORM數據庫框架之-greenDao(一)
- Android ORM數據庫框架之-greenDao(二)
- Android ORM數據庫框架之-greenDao(三)
- Android ORM數據庫框架之-greenDao(四)
- Android 網絡開源庫之-retrofit
- RxJava的簡單學習(學習自扔物線)
- Android ORM框架之-ActiveAndroid的簡單分析