Android ORM数据库框架之-greenDao(三)

来源:互联网 发布:江恩时间周期理论,知乎 编辑:程序博客网 时间:2024/05/22 15:47

关于上篇说到的数据库更新问题,我正在找国外大牛的二次封装的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还支持我们自定义。请移步官方介绍

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}<#ifentity.superclass?has_content> extends ${entity.superclass} </#if><#ifentity.interfacesToImplement?has_content> implements <#list entity.interfacesToImplementas 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,实体,替换掉模板中对应的,输出。关于具体输出的源码,实在是太长了,童鞋们自己看吧。

0 0
原创粉丝点击