From 624e195e120fa77020cf02f047ce456a8ca6dd1b Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Wed, 2 Dec 2015 17:42:29 -0800 Subject: [PATCH 1/6] Add parcelable interface option to generator. All Android requirements to support Parcelable are generated. --- .gitignore | 1 + CHANGELOG.md | 6 +- DaoCore/build.gradle | 4 +- .../java/de/greenrobot/dao/AbstractDao.java | 142 +++++++----------- .../de/greenrobot/dao/internal/SqlUtils.java | 4 +- .../dao/internal/TableStatements.java | 4 +- .../java/de/greenrobot/dao/query/Join.java | 8 - .../de/greenrobot/dao/query/QueryBuilder.java | 10 +- DaoGenerator/build.gradle | 6 +- DaoGenerator/src-template/entity.ftl | 47 +++--- .../greenrobot/daogenerator/DaoGenerator.java | 4 +- .../de/greenrobot/daogenerator/DaoUtil.java | 8 +- .../de/greenrobot/daogenerator/Entity.java | 49 +++--- .../de/greenrobot/daogenerator/Property.java | 128 ++++++++++------ .../de/greenrobot/daogenerator/Schema.java | 3 + .../daogenerator/ToManyWithJoinEntity.java | 8 +- DaoTest/build.gradle | 1 + .../de/greenrobot/daotest/TestEntity.java | 20 +-- .../IndexedStringPerformanceTest.java | 2 +- .../daotest/query/QueryBuilderSimpleTest.java | 10 -- .../gentest/TestDaoGenerator.java | 11 +- README.md | 4 +- settings.gradle | 10 +- 23 files changed, 237 insertions(+), 253 deletions(-) diff --git a/.gitignore b/.gitignore index 20374e4a4..b91594d1b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ out/ build/ local.properties +/bin/ diff --git a/CHANGELOG.md b/CHANGELOG.md index f1548666d..eea4cd151 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,11 @@ Release History --------------- -### V2.1.0 Minor feature and bugfix release (2015-11-12, both core and generator) +### V2.1.0 Minor feature release (2015-09-XX, both core and generator) * Official Robolectric support: workaround for a broken system call in Robolectric triggered by Query.forCurrentThread -* QueryBuilder now allows to create DISTINCT queries to avoid duplicate entities returned * CursorQuery (beta, API might change) -* Deadlock prevention when loading a list of entities while doing concurrent updates * Fixed async queries * Better Android Studio support -* Generator: Possibility to supply custom JavaDoc for entities and their properties +* Added performance tests for: ActiveAndroid, Realm, Parse * Generator: Fixed codeBeforeGetter, added codeBeforeGetterAndSetter ### V2.0.0 Major feature release (2015-07-30, both core and generator) diff --git a/DaoCore/build.gradle b/DaoCore/build.gradle index 4f3e7e2c5..4978cc077 100644 --- a/DaoCore/build.gradle +++ b/DaoCore/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'signing' group = 'de.greenrobot' archivesBaseName = 'greendao' -version = '2.1.0' +version = '2.1.0-SNAPSHOT' sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') @@ -45,7 +45,7 @@ javadoc { failOnError = false classpath += configurations.provided title = " greenDAO ${version} API" - options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2011-2015 greenrobot.de. All Rights Reserved.' + options.bottom = 'Available under the Apache License, Version 2.0 - Copyright © 2011-2013 greenrobot.de. All Rights Reserved.' excludes = ['de/greenrobot/dao/internal','de/greenrobot/dao/Internal*'] } diff --git a/DaoCore/src/main/java/de/greenrobot/dao/AbstractDao.java b/DaoCore/src/main/java/de/greenrobot/dao/AbstractDao.java index d39b306ac..51349dfb9 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/AbstractDao.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/AbstractDao.java @@ -16,19 +16,17 @@ package de.greenrobot.dao; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + import android.database.CrossProcessCursor; import android.database.Cursor; import android.database.CursorWindow; import android.database.DatabaseUtils; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteStatement; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.List; - import de.greenrobot.dao.identityscope.IdentityScope; import de.greenrobot.dao.identityscope.IdentityScopeLong; import de.greenrobot.dao.internal.DaoConfig; @@ -39,12 +37,15 @@ /** * Base class for all DAOs: Implements entity operations like insert, load, delete, and query. - *

+ * * This class is thread-safe. * - * @param Entity type - * @param Primary key (PK) type; use Void if entity does not have exactly one PK * @author Markus + * + * @param + * Entity type + * @param + * Primary key (PK) type; use Void if entity does not have exactly one PK */ /* * When operating on TX, statements, or identity scope the following locking order must be met to avoid deadlocks: @@ -117,7 +118,8 @@ public String[] getNonPkColumns() { /** * Loads and entity for the given PK. * - * @param key a PK value or null + * @param key + * a PK value or null * @return The entity or null, if no entity matched the PK value */ public T load(K key) { @@ -132,13 +134,13 @@ public T load(K key) { } } String sql = statements.getSelectByKey(); - String[] keyArray = new String[]{key.toString()}; + String[] keyArray = new String[] { key.toString() }; Cursor cursor = db.rawQuery(sql, keyArray); return loadUniqueAndCloseCursor(cursor); } public T loadByRowId(long rowId) { - String[] idArray = new String[]{Long.toString(rowId)}; + String[] idArray = new String[] { Long.toString(rowId) }; Cursor cursor = db.rawQuery(statements.getSelectByRowId(), idArray); return loadUniqueAndCloseCursor(cursor); } @@ -188,7 +190,8 @@ protected List loadAllAndCloseCursor(Cursor cursor) { /** * Inserts the given entities in the database using a transaction. * - * @param entities The entities to insert. + * @param entities + * The entities to insert. */ public void insertInTx(Iterable entities) { insertInTx(entities, isEntityUpdateable()); @@ -197,7 +200,8 @@ public void insertInTx(Iterable entities) { /** * Inserts the given entities in the database using a transaction. * - * @param entities The entities to insert. + * @param entities + * The entities to insert. */ public void insertInTx(T... entities) { insertInTx(Arrays.asList(entities), isEntityUpdateable()); @@ -207,8 +211,10 @@ public void insertInTx(T... entities) { * Inserts the given entities in the database using a transaction. The given entities will become tracked if the PK * is set. * - * @param entities The entities to insert. - * @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve performance. + * @param entities + * The entities to insert. + * @param setPrimaryKey + * if true, the PKs of the given will be set after the insert; pass false to improve performance. */ public void insertInTx(Iterable entities, boolean setPrimaryKey) { SQLiteStatement stmt = statements.getInsertStatement(); @@ -219,8 +225,10 @@ public void insertInTx(Iterable entities, boolean setPrimaryKey) { * Inserts or replaces the given entities in the database using a transaction. The given entities will become * tracked if the PK is set. * - * @param entities The entities to insert. - * @param setPrimaryKey if true, the PKs of the given will be set after the insert; pass false to improve performance. + * @param entities + * The entities to insert. + * @param setPrimaryKey + * if true, the PKs of the given will be set after the insert; pass false to improve performance. */ public void insertOrReplaceInTx(Iterable entities, boolean setPrimaryKey) { SQLiteStatement stmt = statements.getInsertOrReplaceStatement(); @@ -230,7 +238,8 @@ public void insertOrReplaceInTx(Iterable entities, boolean setPrimaryKey) { /** * Inserts or replaces the given entities in the database using a transaction. * - * @param entities The entities to insert. + * @param entities + * The entities to insert. */ public void insertOrReplaceInTx(Iterable entities) { insertOrReplaceInTx(entities, isEntityUpdateable()); @@ -239,7 +248,8 @@ public void insertOrReplaceInTx(Iterable entities) { /** * Inserts or replaces the given entities in the database using a transaction. * - * @param entities The entities to insert. + * @param entities + * The entities to insert. */ public void insertOrReplaceInTx(T... entities) { insertOrReplaceInTx(Arrays.asList(entities), isEntityUpdateable()); @@ -359,18 +369,12 @@ protected void updateKeyAfterInsertAndAttach(T entity, long rowId, boolean lock) /** Reads all available rows from the given cursor and returns a list of entities. */ protected List loadAllFromCursor(Cursor cursor) { int count = cursor.getCount(); - if (count == 0) { - return Collections.EMPTY_LIST; - } List list = new ArrayList(count); - CursorWindow window = null; - boolean useFastCursor = false; if (cursor instanceof CrossProcessCursor) { - window = ((CrossProcessCursor) cursor).getWindow(); - if (window != null) { // E.g. Robolectric has no Window at this point + CursorWindow window = ((CrossProcessCursor) cursor).getWindow(); + if (window != null) { // E.g. Roboelectric has no Window at this point if (window.getNumRows() == count) { cursor = new FastCursor(window); - useFastCursor = true; } else { DaoLog.d("Window vs. result size: " + window.getNumRows() + "/" + count); } @@ -382,15 +386,10 @@ protected List loadAllFromCursor(Cursor cursor) { identityScope.lock(); identityScope.reserveRoom(count); } - try { - if (!useFastCursor && window != null && identityScope != null) { - loadAllUnlockOnWindowBounds(cursor, window, list); - } else { - do { - list.add(loadCurrent(cursor, 0, false)); - } while (cursor.moveToNext()); - } + do { + list.add(loadCurrent(cursor, 0, false)); + } while (cursor.moveToNext()); } finally { if (identityScope != null) { identityScope.unlock(); @@ -400,42 +399,6 @@ protected List loadAllFromCursor(Cursor cursor) { return list; } - private void loadAllUnlockOnWindowBounds(Cursor cursor, CursorWindow window, List list) { - int windowEnd = window.getStartPosition() + window.getNumRows(); - for (int row = 0; ; row++) { - list.add(loadCurrent(cursor, 0, false)); - row++; - if (row >= windowEnd) { - window = moveToNextUnlocked(cursor); - if(window == null) { - break; - } - windowEnd = window.getStartPosition() + window.getNumRows(); - } else { - if(!cursor.moveToNext()) { - break; - } - } - } - } - - /** - * Unlock identityScope during cursor.moveToNext() when it is about to fill the window (needs a db connection): - * We should not hold the lock while trying to acquire a db connection to avoid deadlocks. - */ - private CursorWindow moveToNextUnlocked(Cursor cursor) { - identityScope.unlock(); - try { - if(cursor.moveToNext()) { - return ((CrossProcessCursor) cursor).getWindow(); - } else { - return null; - } - } finally { - identityScope.lock(); - } - } - /** Internal use only. Considers identity scope. */ final protected T loadCurrent(Cursor cursor, int offset, boolean lock) { if (identityScopeLong != null) { @@ -617,7 +580,8 @@ private void deleteInTxInternal(Iterable entities, Iterable keys) { /** * Deletes the given entities in the database using a transaction. * - * @param entities The entities to delete. + * @param entities + * The entities to delete. */ public void deleteInTx(Iterable entities) { deleteInTxInternal(entities, null); @@ -626,7 +590,8 @@ public void deleteInTx(Iterable entities) { /** * Deletes the given entities in the database using a transaction. * - * @param entities The entities to delete. + * @param entities + * The entities to delete. */ public void deleteInTx(T... entities) { deleteInTxInternal(Arrays.asList(entities), null); @@ -635,7 +600,8 @@ public void deleteInTx(T... entities) { /** * Deletes all entities with the given keys in the database using a transaction. * - * @param keys Keys of the entities to delete. + * @param keys + * Keys of the entities to delete. */ public void deleteByKeyInTx(Iterable keys) { deleteInTxInternal(null, keys); @@ -644,7 +610,8 @@ public void deleteByKeyInTx(Iterable keys) { /** * Deletes all entities with the given keys in the database using a transaction. * - * @param keys Keys of the entities to delete. + * @param keys + * Keys of the entities to delete. */ public void deleteByKeyInTx(K... keys) { deleteInTxInternal(null, Arrays.asList(keys)); @@ -655,7 +622,7 @@ public void refresh(T entity) { assertSinglePk(); K key = getKeyVerified(entity); String sql = statements.getSelectByKey(); - String[] keyArray = new String[]{key.toString()}; + String[] keyArray = new String[] { key.toString() }; Cursor cursor = db.rawQuery(sql, keyArray); try { boolean available = cursor.moveToFirst(); @@ -716,9 +683,11 @@ protected void updateInsideSynchronized(T entity, SQLiteStatement stmt, boolean /** * Attaches the entity to the identity scope. Calls attachEntity(T entity). * - * @param key Needed only for identity scope, pass null if there's none. - * @param entity The entitiy to attach - */ + * @param key + * Needed only for identity scope, pass null if there's none. + * @param entity + * The entitiy to attach + * */ protected final void attachEntity(K key, T entity, boolean lock) { attachEntity(entity); if (identityScope != null && key != null) { @@ -734,15 +703,17 @@ protected final void attachEntity(K key, T entity, boolean lock) { * Sub classes with relations additionally set the DaoMaster here. Must be called before the entity is attached to * the identity scope. * - * @param entity The entitiy to attach - */ + * @param entity + * The entitiy to attach + * */ protected void attachEntity(T entity) { } /** * Updates the given entities in the database using a transaction. * - * @param entities The entities to insert. + * @param entities + * The entities to insert. */ public void updateInTx(Iterable entities) { SQLiteStatement stmt = statements.getUpdateStatement(); @@ -783,7 +754,8 @@ public void updateInTx(Iterable entities) { /** * Updates the given entities in the database using a transaction. * - * @param entities The entities to update. + * @param entities + * The entities to update. */ public void updateInTx(T... entities) { updateInTx(Arrays.asList(entities)); diff --git a/DaoCore/src/main/java/de/greenrobot/dao/internal/SqlUtils.java b/DaoCore/src/main/java/de/greenrobot/dao/internal/SqlUtils.java index 3e328bc95..b9cdf407e 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/internal/SqlUtils.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/internal/SqlUtils.java @@ -104,12 +104,12 @@ public static String createSqlInsert(String insertInto, String tablename, String } /** Creates an select for given columns with a trailing space */ - public static String createSqlSelect(String tablename, String tableAlias, String[] columns, boolean distinct) { + public static String createSqlSelect(String tablename, String tableAlias, String[] columns) { if (tableAlias == null || tableAlias.length() < 0) { throw new DaoException("Table alias required"); } - StringBuilder builder = new StringBuilder(distinct ? "SELECT DISTINCT " : "SELECT "); + StringBuilder builder = new StringBuilder("SELECT "); SqlUtils.appendColumns(builder, tableAlias, columns).append(" FROM "); builder.append('"').append(tablename).append('"').append(' ').append(tableAlias).append(' '); return builder.toString(); diff --git a/DaoCore/src/main/java/de/greenrobot/dao/internal/TableStatements.java b/DaoCore/src/main/java/de/greenrobot/dao/internal/TableStatements.java index 864b6e04e..9414f1f71 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/internal/TableStatements.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/internal/TableStatements.java @@ -77,7 +77,7 @@ public SQLiteStatement getUpdateStatement() { /** ends with an space to simplify appending to this string. */ public String getSelectAll() { if (selectAll == null) { - selectAll = SqlUtils.createSqlSelect(tablename, "T", allColumns, false); + selectAll = SqlUtils.createSqlSelect(tablename, "T", allColumns); } return selectAll; } @@ -85,7 +85,7 @@ public String getSelectAll() { /** ends with an space to simplify appending to this string. */ public String getSelectKeys() { if (selectKeys == null) { - selectKeys = SqlUtils.createSqlSelect(tablename, "T", pkColumns, false); + selectKeys = SqlUtils.createSqlSelect(tablename, "T", pkColumns); } return selectKeys; } diff --git a/DaoCore/src/main/java/de/greenrobot/dao/query/Join.java b/DaoCore/src/main/java/de/greenrobot/dao/query/Join.java index 04dba3fe2..ab142a068 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/query/Join.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/query/Join.java @@ -80,12 +80,4 @@ public WhereCondition and(WhereCondition cond1, WhereCondition cond2, WhereCondi return whereCollector.combineWhereConditions(" AND ", cond1, cond2, condMore); } - /** - * Usually you don't need this value; just in case you are mixing custom - * {@link de.greenrobot.dao.query.WhereCondition.StringCondition} into the query, this value allows to reference - * the joined (target) table. - */ - public String getTablePrefix() { - return tablePrefix; - } } diff --git a/DaoCore/src/main/java/de/greenrobot/dao/query/QueryBuilder.java b/DaoCore/src/main/java/de/greenrobot/dao/query/QueryBuilder.java index 2e6218381..e6c15ec67 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/query/QueryBuilder.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/query/QueryBuilder.java @@ -58,7 +58,6 @@ public class QueryBuilder { private Integer limit; private Integer offset; - private boolean distinct; /** For internal use by greenDAO only. */ public static QueryBuilder internalCreate(AbstractDao dao) { @@ -85,12 +84,6 @@ private void checkOrderBuilder() { } } - /** Use a SELECT DISTINCT to avoid duplicate entities returned, e.g. when doing joins. */ - public QueryBuilder distinct() { - distinct = true; - return this; - } - /** * Adds the given conditions to the where clause using an logical AND. To create new conditions, use the properties * given in the generated dao classes. @@ -269,7 +262,7 @@ public CursorQuery buildCursor() { } private StringBuilder createSelectBuilder() { - String select = SqlUtils.createSqlSelect(dao.getTablename(), tablePrefix, dao.getAllColumns(), distinct); + String select = SqlUtils.createSqlSelect(dao.getTablename(), tablePrefix, dao.getAllColumns()); StringBuilder builder = new StringBuilder(select); appendJoinsAndWheres(builder, tablePrefix); @@ -280,6 +273,7 @@ private StringBuilder createSelectBuilder() { return builder; } + private int checkAddLimit(StringBuilder builder) { int limitPosition = -1; if (limit != null) { diff --git a/DaoGenerator/build.gradle b/DaoGenerator/build.gradle index 843f81412..ccdbde8b1 100644 --- a/DaoGenerator/build.gradle +++ b/DaoGenerator/build.gradle @@ -4,8 +4,8 @@ apply plugin: 'signing' group = 'de.greenrobot' archivesBaseName = 'greendao-generator' -version = '2.1.1-SNAPSHOT' -sourceCompatibility = 1.7 +version = '2.0.0' +sourceCompatibility = 1.6 def isSnapshot = version.endsWith('-SNAPSHOT') def sonatypeRepositoryUrl @@ -27,7 +27,7 @@ configurations { } dependencies { - compile 'org.freemarker:freemarker:2.3.23' + compile 'org.freemarker:freemarker:2.3.22' testCompile 'junit:junit:4.12' // deployerJars 'org.apache.maven.wagon:wagon-webdav-jackrabbit:2.4' deployerJars 'org.apache.maven.wagon:wagon-webdav:1.0-beta-2' diff --git a/DaoGenerator/src-template/entity.ftl b/DaoGenerator/src-template/entity.ftl index 0e383d847..5fd44b8b0 100644 --- a/DaoGenerator/src-template/entity.ftl +++ b/DaoGenerator/src-template/entity.ftl @@ -44,17 +44,9 @@ import ${additionalImport}; <#else> // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit. -<#if entity.javaDoc ??> - -${entity.javaDoc} -<#else> /** * Entity mapped to table "${entity.tableName}". */ - -<#if entity.codeBeforeClass ??> -${entity.codeBeforeClass} - public class ${entity.className}<#if entity.superclass?has_content> extends ${entity.superclass} <#if entity.interfacesToImplement?has_content> implements <#list entity.interfacesToImplement @@ -64,9 +56,6 @@ as ifc>${ifc}<#if ifc_has_next>, { <#if property.notNull && complexTypes?seq_contains(property.propertyType)> /** Not-null value. */ -<#if property.javaDocField ??> -${property.javaDocField} - <#if property.codeBeforeField ??> ${property.codeBeforeField} @@ -112,6 +101,36 @@ property>${property.javaType} ${property.propertyName}<#if property_has_next>, < } +<#if entity.parcelable> + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { +<#list entity.properties as property> + ${property.parcelableWriteStatement} + + } + + private ${entity.className}(Parcel in) { +<#list entity.properties as property> + ${property.parcelableReadStatement} + + } + + public static final Parcelable.Creator<${entity.className}> CREATOR = new Parcelable.Creator<${entity.className}>() { + public ${entity.className} createFromParcel(Parcel in) { + return new ${entity.className}(in); + } + + public ${entity.className} [] newArray(int size) { + return new ${entity.className}[size]; + } + }; + + public ${entity.className}(<#list entity.properties as property>${property.javaTypeInEntity} ${property.propertyName}<#if property_has_next>, ) { <#list entity.properties as property> @@ -132,9 +151,6 @@ property>${property.javaTypeInEntity} ${property.propertyName}<#if property_has_ <#if property.notNull && complexTypes?seq_contains(property.propertyType)> /** Not-null value. */ -<#if property.javaDocGetter ??> -${property.javaDocGetter} - <#if property.codeBeforeGetter ??> ${property.codeBeforeGetter} @@ -145,9 +161,6 @@ ${property.javaDocGetter} <#if property.notNull && complexTypes?seq_contains(property.propertyType)> /** Not-null value; ensure this value is available before it is saved to the database. */ -<#if property.javaDocSetter ??> -${property.javaDocSetter} - <#if property.codeBeforeSetter ??> ${property.codeBeforeSetter} diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/DaoGenerator.java b/DaoGenerator/src/de/greenrobot/daogenerator/DaoGenerator.java index bb25fe9a1..0828ca40c 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/DaoGenerator.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/DaoGenerator.java @@ -28,6 +28,7 @@ import java.util.regex.Pattern; import freemarker.template.Configuration; +import freemarker.template.DefaultObjectWrapper; import freemarker.template.Template; /** @@ -57,8 +58,9 @@ public DaoGenerator() throws IOException { patternKeepFields = compilePattern("FIELDS"); patternKeepMethods = compilePattern("METHODS"); - Configuration config = new Configuration(Configuration.VERSION_2_3_23); + Configuration config = new Configuration(); config.setClassForTemplateLoading(this.getClass(), "/"); + config.setObjectWrapper(new DefaultObjectWrapper()); templateDao = config.getTemplate("dao.ftl"); templateDaoMaster = config.getTemplate("dao-master.ftl"); diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/DaoUtil.java b/DaoGenerator/src/de/greenrobot/daogenerator/DaoUtil.java index a8a2e9658..feb76469c 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/DaoUtil.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/DaoUtil.java @@ -104,11 +104,5 @@ public static int copyAllBytes(InputStream in, OutputStream out) throws IOExcept return byteCount; } - public static String checkConvertToJavaDoc(String javaDoc, String indent) { - if (javaDoc != null && !javaDoc.trim().startsWith("/**")) { - javaDoc = javaDoc.replace("\n", "\n" + indent + " * "); - javaDoc = indent + "/**\n" + indent + " * " + javaDoc + "\n" + indent + " */"; - } - return javaDoc; - } + } diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Entity.java b/DaoGenerator/src/de/greenrobot/daogenerator/Entity.java index da865a423..2d46158e3 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Entity.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Entity.java @@ -17,6 +17,8 @@ */ package de.greenrobot.daogenerator; +import de.greenrobot.daogenerator.Property.PropertyBuilder; + import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; @@ -24,8 +26,6 @@ import java.util.Set; import java.util.TreeSet; -import de.greenrobot.daogenerator.Property.PropertyBuilder; - /** * Model class for an entity: a Java data object mapped to a data base table. A new entity is added to a {@link Schema} * by the method {@link Schema#addEntity(String)} (there is no public constructor for {@link Entity} itself).
@@ -64,8 +64,6 @@ public class Entity { private Property pkProperty; private String pkType; private String superclass; - private String javaDoc; - private String codeBeforeClass; private boolean protobuf; private boolean constructors; @@ -74,6 +72,7 @@ public class Entity { private boolean skipTableCreation; private Boolean active; private Boolean hasKeepSections; + private boolean parcelable = false; Entity(Schema schema, String className) { this.schema = schema; @@ -444,41 +443,41 @@ public List getContentProviders() { return contentProviders; } - public void implementsInterface(String... interfaces) { + public Entity implementsInterface(String... interfaces) { for (String interfaceToImplement : interfaces) { if (interfacesToImplement.contains(interfaceToImplement)) { throw new RuntimeException("Interface defined more than once: " + interfaceToImplement); } interfacesToImplement.add(interfaceToImplement); } + return this; } public void implementsSerializable() { interfacesToImplement.add("java.io.Serializable"); } + + /** + * Generates all the Android Parcelable methods. Only Fields marked as notNull() will be parceled. + * @return + */ + public Entity implementsParcelable() { + interfacesToImplement.add("Parcelable"); + parcelable = true; + return addImport("android.os.*"); + } + + public boolean isParcelable() { + return parcelable; + } public String getSuperclass() { return superclass; } - public void setSuperclass(String classToExtend) { + public Entity setSuperclass(String classToExtend) { this.superclass = classToExtend; - } - - public String getJavaDoc() { - return javaDoc; - } - - public void setJavaDoc(String javaDoc) { - this.javaDoc = DaoUtil.checkConvertToJavaDoc(javaDoc, ""); - } - - public String getCodeBeforeClass() { - return codeBeforeClass; - } - - public void setCodeBeforeClass(String codeBeforeClass) { - this.codeBeforeClass = codeBeforeClass; + return this; } void init2ndPass() { @@ -596,6 +595,12 @@ void init3rdPass() { init3rdPassRelations(); init3rdPassAdditionalImports(); } + + void initParcelablePass() { + for (Property property: properties) { + property.initParcelableMethods(); + } + } private void init3rdPassRelations() { Set toOneNames = new HashSet(); diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java index 14534df55..3af4607ad 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java @@ -131,32 +131,6 @@ public PropertyBuilder codeBeforeGetterAndSetter(String code) { return this; } - public PropertyBuilder javaDocField(String javaDoc) { - property.javaDocField = checkConvertToJavaDoc(javaDoc); - return this; - } - - private String checkConvertToJavaDoc(String javaDoc) { - return DaoUtil.checkConvertToJavaDoc(javaDoc, " "); - } - - public PropertyBuilder javaDocGetter(String javaDoc) { - property.javaDocGetter = checkConvertToJavaDoc(javaDoc); - return this; - } - - public PropertyBuilder javaDocSetter(String javaDoc) { - property.javaDocSetter = checkConvertToJavaDoc(javaDoc); - return this; - } - - public PropertyBuilder javaDocGetterAndSetter(String javaDoc) { - javaDoc = checkConvertToJavaDoc(javaDoc); - property.javaDocGetter = javaDoc; - property.javaDocSetter = javaDoc; - return this; - } - public Property getProperty() { return property; } @@ -179,10 +153,6 @@ public Property getProperty() { private String codeBeforeGetter; private String codeBeforeSetter; - private String javaDocField; - private String javaDocGetter; - private String javaDocSetter; - private boolean primaryKey; private boolean pkAsc; private boolean pkDesc; @@ -197,6 +167,8 @@ public Property getProperty() { private int ordinal; private String javaType; + private String parcelableWriteStatement = ""; + private String parcelableReadStatement = ""; public Property(Schema schema, Entity entity, PropertyType propertyType, String propertyName) { this.schema = schema; @@ -249,7 +221,15 @@ public String getJavaType() { return javaType; } - public String getJavaTypeInEntity() { + public final String getParcelableWriteStatement() { + return parcelableWriteStatement; + } + + public final String getParcelableReadStatement() { + return parcelableReadStatement; + } + + public String getJavaTypeInEntity() { if (customTypeClassName != null) { return customTypeClassName; } else { @@ -293,18 +273,6 @@ public String getCodeBeforeSetter() { return codeBeforeSetter; } - public String getJavaDocField() { - return javaDocField; - } - - public String getJavaDocGetter() { - return javaDocGetter; - } - - public String getJavaDocSetter() { - return javaDocSetter; - } - public String getDatabaseValueExpression() { return getDatabaseValueExpression(propertyName); } @@ -326,9 +294,9 @@ public String getDatabaseValueExpression(String entityValue) { if (customType != null) { builder.append(')'); } - if (propertyType == PropertyType.Boolean) { + if(propertyType == PropertyType.Boolean) { builder.append(" ? 1L: 0L"); - } else if (propertyType == PropertyType.Date) { + } else if(propertyType == PropertyType.Date) { builder.append(".getTime()"); } return builder.toString(); @@ -345,15 +313,16 @@ public String getEntityValueExpression(String databaseValue) { if (customType != null) { builder.append(propertyName).append("Converter.convertToEntityProperty("); } - if (propertyType == PropertyType.Byte) { + if(propertyType == PropertyType.Byte) { builder.append("(byte) "); - } else if (propertyType == PropertyType.Date) { + }else + if(propertyType == PropertyType.Date) { builder.append("new java.util.Date("); } builder.append(databaseValue); - if (propertyType == PropertyType.Boolean) { + if(propertyType == PropertyType.Boolean) { builder.append(" != 0"); - } else if (propertyType == PropertyType.Date) { + } else if(propertyType == PropertyType.Date) { builder.append(")"); } if (customType != null) { @@ -412,6 +381,67 @@ private void initConstraint() { void init3ndPass() { // Nothing to do so far } + + void initParcelableMethods() { + switch (propertyType) { + case Boolean: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readByte() != 0;"; + parcelableWriteStatement = "out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; + } + break; + case Byte: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readByte();"; + parcelableWriteStatement = "out.writeByte(" + propertyName + ");"; + } + break; + case ByteArray: + if (notNull) { + parcelableReadStatement = propertyName + "in.readByteArray(" + propertyName + ");"; + parcelableWriteStatement = "out.writeByteArray(" + propertyName + ");"; + } + break; + case Date: + parcelableReadStatement = propertyName + " = new java.util.Date(in.readLong());"; + parcelableWriteStatement = "out.writeLong(" + propertyName + " == null ? 0 : " + propertyName + ".getTime());"; + break; + case Double: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readDouble();"; + parcelableWriteStatement = "out.writeDouble(" + propertyName + ");"; + } + break; + case Float: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readFloat();"; + parcelableWriteStatement = "out.writeFloat(" + propertyName + ");"; + } + break; + case Int: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readInt();"; + parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; + } + break; + case Long: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readLong();"; + parcelableWriteStatement = "out.writeLong(" + propertyName + ");"; + } + break; + case Short: + if (notNull) { + parcelableReadStatement = propertyName + " = in.readInt();"; + parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; + } + break; + case String: + parcelableReadStatement = propertyName + " = in.readString();"; + parcelableWriteStatement = "out.writeString(" + propertyName + ");"; + break; + } + } @Override public String toString() { diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Schema.java b/DaoGenerator/src/de/greenrobot/daogenerator/Schema.java index 8351ecb55..236a17687 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Schema.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Schema.java @@ -183,6 +183,9 @@ void init2ndPass() { void init3rdPass() { for (Entity entity : entities) { entity.init3rdPass(); + if (entity.isParcelable()) { + entity.initParcelablePass(); + } } } diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/ToManyWithJoinEntity.java b/DaoGenerator/src/de/greenrobot/daogenerator/ToManyWithJoinEntity.java index 0f897f054..752215669 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/ToManyWithJoinEntity.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/ToManyWithJoinEntity.java @@ -45,8 +45,8 @@ public Property getTargetProperty() { return targetProperty; } - void init3rdPass() { - super.init3rdPass(); + void init2ndPass() { + super.init2ndPass(); List pks = sourceEntity.getPropertiesPk(); if (pks.isEmpty()) { throw new RuntimeException("Source entity has no primary key, but we need it for " + this); @@ -57,4 +57,8 @@ void init3rdPass() { } } + void init3rdPass() { + super.init3rdPass(); + } + } diff --git a/DaoTest/build.gradle b/DaoTest/build.gradle index 0947debdd..74707af29 100644 --- a/DaoTest/build.gradle +++ b/DaoTest/build.gradle @@ -12,6 +12,7 @@ apply plugin: 'com.android.application' dependencies { androidTestCompile project(':DaoCore') + androidTestCompile project(':PerformanceTests:Common') testCompile project(':DaoCore') testCompile 'org.robolectric:robolectric:3.0' diff --git a/DaoTest/src-gen/de/greenrobot/daotest/TestEntity.java b/DaoTest/src-gen/de/greenrobot/daotest/TestEntity.java index 15863049b..748cee08a 100644 --- a/DaoTest/src-gen/de/greenrobot/daotest/TestEntity.java +++ b/DaoTest/src-gen/de/greenrobot/daotest/TestEntity.java @@ -1,17 +1,11 @@ package de.greenrobot.daotest; // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit. - /** - * This entity is used by internal tests of greenDAO. - * (This JavaDoc is defined in the generator project.) + * Entity mapped to table "TEST_ENTITY". */ -// This is another test comment, you could also apply annotations like this public class TestEntity { - /** - * JavaDoc test field - */ private Long id; private int simpleInt; private Integer simpleInteger; @@ -52,9 +46,6 @@ public void setId(Long id) { this.id = id; } - /** - * JavaDoc test getter - */ public int getSimpleInt() { return simpleInt; } @@ -67,25 +58,16 @@ public Integer getSimpleInteger() { return simpleInteger; } - /** - * JavaDoc test setter - */ public void setSimpleInteger(Integer simpleInteger) { this.simpleInteger = simpleInteger; } /** Not-null value. */ - /** - * JavaDoc test getter and setter - */ public String getSimpleStringNotNull() { return simpleStringNotNull; } /** Not-null value; ensure this value is available before it is saved to the database. */ - /** - * JavaDoc test getter and setter - */ public void setSimpleStringNotNull(String simpleStringNotNull) { this.simpleStringNotNull = simpleStringNotNull; } diff --git a/DaoTest/src/de/greenrobot/daotest/performance/IndexedStringPerformanceTest.java b/DaoTest/src/de/greenrobot/daotest/performance/IndexedStringPerformanceTest.java index dfb30b633..1a0822ec3 100644 --- a/DaoTest/src/de/greenrobot/daotest/performance/IndexedStringPerformanceTest.java +++ b/DaoTest/src/de/greenrobot/daotest/performance/IndexedStringPerformanceTest.java @@ -4,7 +4,7 @@ import de.greenrobot.dao.test.AbstractDaoTest; import de.greenrobot.daotest.IndexedStringEntity; import de.greenrobot.daotest.IndexedStringEntityDao; - +import de.greenrobot.performance.StringGenerator; import java.util.ArrayList; import java.util.List; diff --git a/DaoTest/src/de/greenrobot/daotest/query/QueryBuilderSimpleTest.java b/DaoTest/src/de/greenrobot/daotest/query/QueryBuilderSimpleTest.java index 221a80bde..a8dbcc4bc 100644 --- a/DaoTest/src/de/greenrobot/daotest/query/QueryBuilderSimpleTest.java +++ b/DaoTest/src/de/greenrobot/daotest/query/QueryBuilderSimpleTest.java @@ -250,14 +250,4 @@ public void testLike() { assertNull(entity2); } - public void testDistinct() { - TestEntity entity = insert(3).get(1); - - Query query = dao.queryBuilder().distinct() - .where(Properties.SimpleString.eq(entity.getSimpleString())).build(); - TestEntity entity2 = query.uniqueOrThrow(); - assertEquals(entity.getId(), entity2.getId()); - // TODO improve test to check functionality - } - } diff --git a/DaoTestGenerator/src/de/greenrobot/daogenerator/gentest/TestDaoGenerator.java b/DaoTestGenerator/src/de/greenrobot/daogenerator/gentest/TestDaoGenerator.java index f42d1d36e..88ba60800 100644 --- a/DaoTestGenerator/src/de/greenrobot/daogenerator/gentest/TestDaoGenerator.java +++ b/DaoTestGenerator/src/de/greenrobot/daogenerator/gentest/TestDaoGenerator.java @@ -105,13 +105,10 @@ protected void createSimpleNotNull() { protected Entity createTest() { Entity testEntity = schema.addEntity("TestEntity"); - testEntity.setJavaDoc("This entity is used by internal tests of greenDAO.\n" + - "(This JavaDoc is defined in the generator project.)"); - testEntity.setCodeBeforeClass("// This is another test comment, you could also apply annotations like this"); - testEntity.addIdProperty().javaDocField("JavaDoc test field"); - testEntity.addIntProperty("simpleInt").notNull().javaDocGetter("JavaDoc test getter"); - testEntity.addIntProperty("simpleInteger").javaDocSetter("JavaDoc test setter"); - testEntity.addStringProperty("simpleStringNotNull").notNull().javaDocGetterAndSetter("JavaDoc test getter and setter"); + testEntity.addIdProperty(); + testEntity.addIntProperty("simpleInt").notNull(); + testEntity.addIntProperty("simpleInteger"); + testEntity.addStringProperty("simpleStringNotNull").notNull(); testEntity.addStringProperty("simpleString"); testEntity.addStringProperty("indexedString").index(); testEntity.addStringProperty("indexedStringAscUnique").indexAsc(null, true); diff --git a/README.md b/README.md index 5df7e6941..2560bd888 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,8 @@ -**Please help us with this short survey: http://bit.ly/greendao-survey Thanks for your support!** - greenDAO ======== greenDAO is a light & fast ORM solution for Android that maps objects to SQLite databases. Being highly optimized for Android, greenDAO offers great performance and consumes minimal memory. -**Home page, documentation, and support links: http://greenrobot.org/greendao/** +**Home page, documentation, and support links: http://greendao-orm.com/** [![Build Status](https://travis-ci.org/greenrobot/greenDAO.svg?branch=master)](https://travis-ci.org/greenrobot/greenDAO) diff --git a/settings.gradle b/settings.gradle index ef5f41d27..660b6cd5b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,4 +2,12 @@ include 'DaoCore', 'DaoGenerator', 'DaoExampleGenerator' include 'DaoTest' // Travis needs some Android setup for this include 'DaoTestGenerator' include ':DaoExample' - +include ':PerformanceTests:Common' +include ':PerformanceTests:ActiveAndroid' +include ':PerformanceTests:Couchbase' +include ':PerformanceTests:Cupboard' +include ':PerformanceTests:Firebase' +include ':PerformanceTests:OrmLite' +include ':PerformanceTests:Parse' +include ':PerformanceTests:Realm' +include ':PerformanceTests:Sqlite' From aa5a989ead14a758846c024bec5cac8074203c00 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Thu, 10 Dec 2015 16:16:46 -0800 Subject: [PATCH 2/6] Add ability to automate ALTER TABLE statements for the basic case of just adding a field. Described in issue GreenDao #272 --- .../main/java/de/greenrobot/dao/Property.java | 6 ++- DaoGenerator/src-template/dao-master.ftl | 50 +++++++++++++++++++ DaoGenerator/src-template/dao.ftl | 21 +++++++- .../de/greenrobot/daogenerator/Property.java | 14 ++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/DaoCore/src/main/java/de/greenrobot/dao/Property.java b/DaoCore/src/main/java/de/greenrobot/dao/Property.java index 77923eb71..eddd6e405 100644 --- a/DaoCore/src/main/java/de/greenrobot/dao/Property.java +++ b/DaoCore/src/main/java/de/greenrobot/dao/Property.java @@ -33,13 +33,17 @@ public class Property { public final String name; public final boolean primaryKey; public final String columnName; + public final String sqlType; + public final int version; - public Property(int ordinal, Class type, String name, boolean primaryKey, String columnName) { + public Property(int ordinal, Class type, String name, boolean primaryKey, String columnName, String sqlType, int version) { this.ordinal = ordinal; this.type = type; this.name = name; this.primaryKey = primaryKey; this.columnName = columnName; + this.sqlType = sqlType; + this.version = version; } /** Creates an "equal ('=')" condition for this property. */ diff --git a/DaoGenerator/src-template/dao-master.ftl b/DaoGenerator/src-template/dao-master.ftl index adaffc487..6f6bd55e3 100644 --- a/DaoGenerator/src-template/dao-master.ftl +++ b/DaoGenerator/src-template/dao-master.ftl @@ -81,6 +81,56 @@ public class DaoMaster extends AbstractDaoMaster { dropAllTables(db, true); onCreate(db); } + + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class AutoUpdateOpenHelper extends OpenHelper { + public AutoUpdateOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.beginTransaction(); + try { +<#list schema.entities as entity> + ${entity.classNameDao}.updateTable(db, oldVersion, newVersion); + + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + } + + } + + } + + /** WARNING: Drops all table on Upgrade! Use only during development. */ + public static class DevAutoUpdateOpenHelper extends OpenHelper { + public DevAutoUpdateOpenHelper(Context context, String name, CursorFactory factory) { + super(context, name, factory); + } + + @Override + public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { + db.beginTransaction(); + try { +<#list schema.entities as entity> + ${entity.classNameDao}.updateTable(db, oldVersion, newVersion); + + + } catch (Exception e) { + e.printStackTrace(); + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); + dropAllTables(db, true); + onCreate(db); + } finally { + db.endTransaction(); + } + + } + } public DaoMaster(SQLiteDatabase db) { diff --git a/DaoGenerator/src-template/dao.ftl b/DaoGenerator/src-template/dao.ftl index 60f7045b1..6024b86f8 100644 --- a/DaoGenerator/src-template/dao.ftl +++ b/DaoGenerator/src-template/dao.ftl @@ -30,6 +30,7 @@ import java.util.ArrayList; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteStatement; +import android.util.Log; import de.greenrobot.dao.AbstractDao; import de.greenrobot.dao.Property; @@ -64,6 +65,8 @@ import ${entity.javaPackage}.${entity.className}.Builder; public class ${entity.classNameDao} extends AbstractDao<${entity.className}, ${entity.pkType}> { public static final String TABLENAME = "${entity.tableName}"; + + public static final String TAG = "${entity.classNameDao}"; /** * Properties of entity ${entity.className}.
@@ -71,8 +74,15 @@ public class ${entity.classNameDao} extends AbstractDao<${entity.className}, ${e */ public static class Properties { <#list entity.propertiesColumns as property> - public final static Property ${property.propertyName?cap_first} = new Property(${property_index}, ${property.javaType}.class, "${property.propertyName}", ${property.primaryKey?string}, "${property.columnName}"); + public final static Property ${property.propertyName?cap_first} = new Property(${property_index}, ${property.javaType}.class, "${property.propertyName}", ${property.primaryKey?string}, "${property.columnName}", "${property.columnType}", ${property.version}); + + public final static Property [] all = { +<#list entity.propertiesColumns as property> + ${property.propertyName?cap_first}, + + }; + }; <#if entity.active> @@ -114,6 +124,15 @@ as property>\"${property.columnName}\"<#if property_has_next>,);") } + + public static void updateTable(SQLiteDatabase db, int oldVer, int newVer) { + for (Property p : Properties.all) { + if (p.version > oldVer) { + Log.i(TAG, "Alter table " + TABLENAME + " add column '" + p.columnName + "' " + p.sqlType); + db.execSQL("ALTER TABLE \"" + TABLENAME + "\" ADD \"" + p.columnName + "\" " + p.sqlType); + } + } + } /** Drops the underlying database table. */ public static void dropTable(SQLiteDatabase db, boolean ifExists) { diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java index 3af4607ad..7045a9706 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java @@ -134,6 +134,10 @@ public PropertyBuilder codeBeforeGetterAndSetter(String code) { public Property getProperty() { return property; } + + public void setVersion(int versionDontForgetToBump) { + property.version = versionDontForgetToBump; + } } private final Schema schema; @@ -169,6 +173,8 @@ public Property getProperty() { private String javaType; private String parcelableWriteStatement = ""; private String parcelableReadStatement = ""; + + private int version = -1; public Property(Schema schema, Entity entity, PropertyType propertyType, String propertyName) { this.schema = schema; @@ -280,6 +286,14 @@ public String getDatabaseValueExpression() { public String getDatabaseValueExpressionNotNull() { return getDatabaseValueExpression("entity.get" + DaoUtil.capFirst(propertyName) + "()"); } + + /** + * version this field was added. can be used in the onUpgrade callback to auto update. + * @return + */ + public String getVersion() { + return String.valueOf(version); + } // Got too messy in template: // <#if property.customType?has_content>${property.propertyName}Converter.convertToDatabaseValue(<#-- From 89ad1ea6edb5c5c6b1e80149f3596de139705405 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sun, 16 Oct 2016 09:37:07 -0700 Subject: [PATCH 3/6] Fix not parceling null fields --- .../de/greenrobot/daogenerator/Property.java | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java index 7045a9706..61c4f1aaa 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java @@ -135,8 +135,8 @@ public Property getProperty() { return property; } - public void setVersion(int versionDontForgetToBump) { - property.version = versionDontForgetToBump; + public void setVersion(int rawVersionDontForgetToBump) { + property.version = rawVersionDontForgetToBump; } } @@ -399,15 +399,19 @@ void init3ndPass() { void initParcelableMethods() { switch (propertyType) { case Boolean: + parcelableReadStatement = propertyName + " = in.readByte() != 0;"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readByte() != 0;"; parcelableWriteStatement = "out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte(0); else out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; } break; case Byte: if (notNull) { parcelableReadStatement = propertyName + " = in.readByte();"; parcelableWriteStatement = "out.writeByte(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte(0); else out.writeByte(" + propertyName + ");"; } break; case ByteArray: @@ -424,30 +428,40 @@ void initParcelableMethods() { if (notNull) { parcelableReadStatement = propertyName + " = in.readDouble();"; parcelableWriteStatement = "out.writeDouble(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeDouble(0); else out.writeDouble(" + propertyName + ");"; } break; case Float: if (notNull) { parcelableReadStatement = propertyName + " = in.readFloat();"; parcelableWriteStatement = "out.writeFloat(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeFloat(0); else out.writeFloat(" + propertyName + ");"; } break; case Int: if (notNull) { parcelableReadStatement = propertyName + " = in.readInt();"; parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeInt(0); else out.writeInt(" + propertyName + ");"; } break; case Long: if (notNull) { parcelableReadStatement = propertyName + " = in.readLong();"; parcelableWriteStatement = "out.writeLong(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeLong(0); else out.writeLong(" + propertyName + ");"; } break; case Short: if (notNull) { parcelableReadStatement = propertyName + " = in.readInt();"; parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; + } else { + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeInt(0); else out.writeInt(" + propertyName + ");"; } break; case String: From 58e5c5ce3defa4e45737cc18a8155a9b5e062429 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sun, 16 Oct 2016 09:58:28 -0700 Subject: [PATCH 4/6] Fix not reading nullable parcelables --- .../src/de/greenrobot/daogenerator/Property.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java index 61c4f1aaa..d3a3786ca 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java @@ -407,8 +407,8 @@ void initParcelableMethods() { } break; case Byte: + parcelableReadStatement = propertyName + " = in.readByte();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readByte();"; parcelableWriteStatement = "out.writeByte(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte(0); else out.writeByte(" + propertyName + ");"; @@ -425,40 +425,40 @@ void initParcelableMethods() { parcelableWriteStatement = "out.writeLong(" + propertyName + " == null ? 0 : " + propertyName + ".getTime());"; break; case Double: + parcelableReadStatement = propertyName + " = in.readDouble();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readDouble();"; parcelableWriteStatement = "out.writeDouble(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeDouble(0); else out.writeDouble(" + propertyName + ");"; } break; case Float: + parcelableReadStatement = propertyName + " = in.readFloat();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readFloat();"; parcelableWriteStatement = "out.writeFloat(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeFloat(0); else out.writeFloat(" + propertyName + ");"; } break; case Int: + parcelableReadStatement = propertyName + " = in.readInt();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readInt();"; parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeInt(0); else out.writeInt(" + propertyName + ");"; } break; case Long: + parcelableReadStatement = propertyName + " = in.readLong();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readLong();"; parcelableWriteStatement = "out.writeLong(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeLong(0); else out.writeLong(" + propertyName + ");"; } break; case Short: + parcelableReadStatement = propertyName + " = in.readInt();"; if (notNull) { - parcelableReadStatement = propertyName + " = in.readInt();"; parcelableWriteStatement = "out.writeInt(" + propertyName + ");"; } else { parcelableWriteStatement = "if (" + propertyName + " == null) out.writeInt(0); else out.writeInt(" + propertyName + ");"; From 79a9fbdde5b80c1f76c10bd8f2ba26611924d0e8 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Mon, 5 Dec 2016 13:08:46 -0800 Subject: [PATCH 5/6] write write boolean --- DaoGenerator/src/de/greenrobot/daogenerator/Property.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java index d3a3786ca..a7bdc48a8 100644 --- a/DaoGenerator/src/de/greenrobot/daogenerator/Property.java +++ b/DaoGenerator/src/de/greenrobot/daogenerator/Property.java @@ -403,7 +403,7 @@ void initParcelableMethods() { if (notNull) { parcelableWriteStatement = "out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; } else { - parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte(0); else out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte((byte)0); else out.writeByte((byte)(" + propertyName + " ? 1 : 0));"; } break; case Byte: @@ -411,7 +411,7 @@ void initParcelableMethods() { if (notNull) { parcelableWriteStatement = "out.writeByte(" + propertyName + ");"; } else { - parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte(0); else out.writeByte(" + propertyName + ");"; + parcelableWriteStatement = "if (" + propertyName + " == null) out.writeByte((byte)0); else out.writeByte(" + propertyName + ");"; } break; case ByteArray: From f89341d317a58dbf3bf73f071087fb51c9f97e51 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Wed, 5 Apr 2017 14:28:26 -0700 Subject: [PATCH 6/6] Add logic to skip columns if they exist. This is to support case when we are doing an upgrade across multiple version changes where an create table would be called followed by an alter table which would fail because the create table is complete. --- DaoGenerator/src-template/dao.ftl | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/DaoGenerator/src-template/dao.ftl b/DaoGenerator/src-template/dao.ftl index 6024b86f8..bdf9a272a 100644 --- a/DaoGenerator/src-template/dao.ftl +++ b/DaoGenerator/src-template/dao.ftl @@ -128,6 +128,22 @@ as property>\"${property.columnName}\"<#if property_has_next>,);") public static void updateTable(SQLiteDatabase db, int oldVer, int newVer) { for (Property p : Properties.all) { if (p.version > oldVer) { + Cursor cursor = db.rawQuery("PRAGMA table_info("+ TABLENAME +")", null); + if (cursor != null) { + boolean skip = false; + while (cursor.moveToNext()) { + String name = cursor.getString(cursor.getColumnIndex("name")); + if (p.columnName.equalsIgnoreCase(name)) { + skip = true; + break; + } + } + if (skip) { + Log.w(TAG, "Skipping add column '" + p.columnName + "' because already exists"); + continue; + } + cursor.close(); + } Log.i(TAG, "Alter table " + TABLENAME + " add column '" + p.columnName + "' " + p.sqlType); db.execSQL("ALTER TABLE \"" + TABLENAME + "\" ADD \"" + p.columnName + "\" " + p.sqlType); }