From 36649d5514aae4b006ce3d6bff0028507ecba1da Mon Sep 17 00:00:00 2001 From: Satya Narayan Date: Tue, 15 Jul 2014 20:42:06 -0700 Subject: [PATCH] introduced Table annotation to handle custom table naming and removing the SugarRecord dependency --- example/src/com/example/Note.java | 14 +- example/src/com/example/SugarActivity.java | 11 +- library/src/com/orm/StringUtil.java | 69 ++++--- library/src/com/orm/SugarDb.java | 137 +++++++------- library/src/com/orm/SugarRecord.java | 206 ++++++++------------- library/src/com/orm/dsl/Table.java | 9 + library/src/com/orm/query/Select.java | 3 +- 7 files changed, 215 insertions(+), 234 deletions(-) create mode 100644 library/src/com/orm/dsl/Table.java diff --git a/example/src/com/example/Note.java b/example/src/com/example/Note.java index 8e6308f9..0ede586c 100755 --- a/example/src/com/example/Note.java +++ b/example/src/com/example/Note.java @@ -2,7 +2,9 @@ import com.orm.SugarRecord; import com.orm.dsl.Column; +import com.orm.dsl.Table; +@Table(name = "Note") public class Note extends SugarRecord{ @Column(name = "noteId", unique = true, notNull = true) @@ -42,20 +44,20 @@ public String getTitle() { return title; } - public String getDescription() { - return description; + public void setTitle(String title) { + this.title = title; } - public Tag getTag() { - return tag; + public String getDescription() { + return description; } public void setDescription(String description){ this.description = description; } - public void setTitle(String title) { - this.title = title; + public Tag getTag() { + return tag; } @Override diff --git a/example/src/com/example/SugarActivity.java b/example/src/com/example/SugarActivity.java index f5b8fe9f..88b0d29c 100755 --- a/example/src/com/example/SugarActivity.java +++ b/example/src/com/example/SugarActivity.java @@ -2,11 +2,8 @@ import android.app.Activity; import android.content.Intent; -import android.database.sqlite.SQLiteDatabase; import android.os.Bundle; -import android.util.Log; -import com.orm.Database; -import com.orm.SugarApp; +import com.orm.SugarRecord; public class SugarActivity extends Activity { @@ -16,9 +13,9 @@ public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); - Note.deleteAll(Note.class); - TextNote.deleteAll(TextNote.class); - Tag.deleteAll(Tag.class); + SugarRecord.deleteAll(Note.class); + SugarRecord.deleteAll(TextNote.class); + SugarRecord.deleteAll(Tag.class); initDb(); Intent intent = new Intent(this, NoteListActivity.class); startActivity(intent); diff --git a/library/src/com/orm/StringUtil.java b/library/src/com/orm/StringUtil.java index 4f837a1b..2c9767ff 100644 --- a/library/src/com/orm/StringUtil.java +++ b/library/src/com/orm/StringUtil.java @@ -1,50 +1,59 @@ package com.orm; import com.orm.dsl.Column; +import com.orm.dsl.Table; import java.lang.reflect.Field; public class StringUtil { public static String toSQLNameDefault(String javaNotation) { - if(javaNotation.equalsIgnoreCase("_id")) - return "_id"; - - StringBuilder sb = new StringBuilder(); - char[] buf = javaNotation.toCharArray(); - - for (int i = 0; i < buf.length; i++) { - char prevChar = (i > 0) ? buf[i - 1] : 0; - char c = buf[i]; - char nextChar = (i < buf.length - 1) ? buf[i + 1] : 0; - boolean isFirstChar = (i == 0); - - if (isFirstChar || Character.isLowerCase(c) || Character.isDigit(c)) { - sb.append(Character.toUpperCase(c)); - } else if (Character.isUpperCase(c)) { - if (Character.isLetterOrDigit(prevChar)) { - if (Character.isLowerCase(prevChar)) { - sb.append('_').append(Character.toUpperCase(c)); - } else if (nextChar > 0 && Character.isLowerCase(nextChar)) { - sb.append('_').append(Character.toUpperCase(c)); - } else { - sb.append(c); - } - } - else { - sb.append(c); - } + if (javaNotation.equalsIgnoreCase("_id")) + return "_id"; + + StringBuilder sb = new StringBuilder(); + char[] buf = javaNotation.toCharArray(); + + for (int i = 0; i < buf.length; i++) { + char prevChar = (i > 0) ? buf[i - 1] : 0; + char c = buf[i]; + char nextChar = (i < buf.length - 1) ? buf[i + 1] : 0; + boolean isFirstChar = (i == 0); + + if (isFirstChar || Character.isLowerCase(c) || Character.isDigit(c)) { + sb.append(Character.toUpperCase(c)); + } else if (Character.isUpperCase(c)) { + if (Character.isLetterOrDigit(prevChar)) { + if (Character.isLowerCase(prevChar)) { + sb.append('_').append(Character.toUpperCase(c)); + } else if (nextChar > 0 && Character.isLowerCase(nextChar)) { + sb.append('_').append(Character.toUpperCase(c)); + } else { + sb.append(c); } + } else { + sb.append(c); + } } + } - return sb.toString(); + return sb.toString(); } - public static String toSQLName(Field field){ - if(field.isAnnotationPresent(Column.class)){ + public static String toSQLName(Field field) { + if (field.isAnnotationPresent(Column.class)) { Column annotation = field.getAnnotation(Column.class); return annotation.name(); } return toSQLNameDefault(field.getName()); } + + public static String toSQLName(Class table) { + + if (table.isAnnotationPresent(Table.class)) { + Table annotation = table.getAnnotation(Table.class); + return annotation.name(); + } + return StringUtil.toSQLNameDefault(table.getSimpleName()); + } } diff --git a/library/src/com/orm/SugarDb.java b/library/src/com/orm/SugarDb.java index ceab2243..0b3db0de 100644 --- a/library/src/com/orm/SugarDb.java +++ b/library/src/com/orm/SugarDb.java @@ -1,35 +1,22 @@ package com.orm; -import static com.orm.SugarConfig.getDatabaseVersion; -import static com.orm.SugarConfig.getDebugEnabled; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Modifier; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.List; - import android.content.Context; import android.content.pm.PackageManager; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteException; import android.database.sqlite.SQLiteOpenHelper; import android.util.Log; +import com.orm.dsl.*; +import dalvik.system.DexFile; -import com.orm.dsl.Column; -import com.orm.dsl.NotNull; -import com.orm.dsl.Unique; +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.URL; +import java.util.*; -import dalvik.system.DexFile; +import static com.orm.SugarConfig.getDatabaseVersion; +import static com.orm.SugarConfig.getDebugEnabled; public class SugarDb extends SQLiteOpenHelper { private Context context; @@ -40,16 +27,45 @@ public SugarDb(Context context) { } - private > List getDomainClasses(Context context) { - List domainClasses = new ArrayList(); + public static List getTableFields(Class table) { + List fieldList = SugarConfig.getFields(table); + if (fieldList != null) return fieldList; + + Log.d("Sugar", "Fetching properties"); + List typeFields = new ArrayList(); + + getAllFields(typeFields, table); + + List toStore = new ArrayList(); + for (Field field : typeFields) { + if (!field.isAnnotationPresent(Ignore.class) && !Modifier.isStatic(field.getModifiers()) && !Modifier.isTransient(field.getModifiers())) { + toStore.add(field); + } + } + + SugarConfig.setFields(table, toStore); + return toStore; + } + + private static List getAllFields(List fields, Class type) { + Collections.addAll(fields, type.getDeclaredFields()); + + if (type.getSuperclass() != null) { + fields = getAllFields(fields, type.getSuperclass()); + } + + return fields; + } + + private List getDomainClasses(Context context) { + List domainClasses = new ArrayList(); try { for (String className : getAllClasses(context)) { if (className.startsWith(SugarConfig.getDomainPackageName(context))) { - T domainClass = getDomainClass(className, context); + Class domainClass = getDomainClass(className, context); if (domainClass != null) domainClasses.add(domainClass); } } - } catch (IOException e) { Log.e("Sugar", e.getMessage()); } catch (PackageManager.NameNotFoundException e) { @@ -59,8 +75,7 @@ private > List getDomainClasses(Context context) { return domainClasses; } - @SuppressWarnings("unchecked") - private > T getDomainClass(String className, Context context) { + private Class getDomainClass(String className, Context context) { Class discoveredClass = null; try { discoveredClass = Class.forName(className, true, context.getClass().getClassLoader()); @@ -68,29 +83,18 @@ private > T getDomainClass(String className, Context co Log.e("Sugar", e.getMessage()); } - if ((discoveredClass == null) || - (!SugarRecord.class.isAssignableFrom(discoveredClass)) || - SugarRecord.class.equals(discoveredClass) || - Modifier.isAbstract(discoveredClass.getModifiers())) { - return null; - } else { - try { - Log.i("Sugar", "domain class : " + discoveredClass.getSimpleName()); - return (T) discoveredClass.getDeclaredConstructor().newInstance(); - - } catch (InstantiationException e) { - Log.e("Sugar", e.getMessage()); - } catch (IllegalAccessException e) { - Log.e("Sugar", e.getMessage()); - } catch (NoSuchMethodException e) { - Log.e("Sugar", e.getMessage()); - } catch (InvocationTargetException e) { - Log.e("Sugar", e.getMessage()); - } - } + if ((discoveredClass != null) && + ((SugarRecord.class.isAssignableFrom(discoveredClass) && + !SugarRecord.class.equals(discoveredClass)) || + discoveredClass.isAnnotationPresent(Table.class)) && + !Modifier.isAbstract(discoveredClass.getModifiers())) { - return null; + Log.i("Sugar", "domain class : " + discoveredClass.getSimpleName()); + return discoveredClass; + } else { + return null; + } } private List getAllClasses(Context context) throws PackageManager.NameNotFoundException, IOException { @@ -119,7 +123,7 @@ private List getAllClasses(Context context) throws PackageManager.NameNo } return classNames; } - + private void populateFiles(File path, List fileNames, String parent) { if (path.isDirectory()) { for (File newPath : path.listFiles()) { @@ -152,17 +156,20 @@ public void onCreate(SQLiteDatabase sqLiteDatabase) { createDatabase(sqLiteDatabase); } - private > void createDatabase(SQLiteDatabase sqLiteDatabase) { - List domainClasses = getDomainClasses(context); - for (T domain : domainClasses) { + private void createDatabase(SQLiteDatabase sqLiteDatabase) { + List domainClasses = getDomainClasses(context); + for (Class domain : domainClasses) { createTable(domain, sqLiteDatabase); } } - private > void createTable(T table, SQLiteDatabase sqLiteDatabase) { + private > void createTable(Class table, SQLiteDatabase sqLiteDatabase) { Log.i("Sugar", "create table"); - List fields = table.getTableFields(); - StringBuilder sb = new StringBuilder("CREATE TABLE ").append(table.getSqlName()).append( + List fields = getTableFields(table); + + String tableName = StringUtil.toSQLName(table); + + StringBuilder sb = new StringBuilder("CREATE TABLE ").append(tableName).append( " ( ID INTEGER PRIMARY KEY AUTOINCREMENT "); for (Field column : fields) { @@ -211,7 +218,7 @@ private > void createTable(T table, SQLiteDatabase sqLi } sb.append(" ) "); - Log.i("Sugar", "creating table " + table.getSqlName()); + Log.i("Sugar", "creating table " + tableName); if (!"".equals(sb.toString())) sqLiteDatabase.execSQL(sb.toString()); @@ -232,11 +239,11 @@ public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVers /** * Create the tables that do not exist. */ - private > void doUpgrade(SQLiteDatabase sqLiteDatabase) { - List domainClasses = getDomainClasses(context); - for (T domain : domainClasses) { + private void doUpgrade(SQLiteDatabase sqLiteDatabase) { + List domainClasses = getDomainClasses(context); + for (Class domain : domainClasses) { try {// we try to do a select, if fails then (?) there isn't the table - sqLiteDatabase.query(domain.tableName, null, null, null, null, null, null); + sqLiteDatabase.query(StringUtil.toSQLName(domain), null, null, null, null, null, null); } catch (SQLiteException e) { Log.i("Sugar", String.format("creating table on update (error was '%s')", e.getMessage())); createTable(domain, sqLiteDatabase); @@ -244,10 +251,10 @@ private > void doUpgrade(SQLiteDatabase sqLiteDatabase) } } - private > void deleteTables(SQLiteDatabase sqLiteDatabase) { - List tables = getDomainClasses(this.context); - for (T table : tables) { - sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + table.getSqlName()); + private void deleteTables(SQLiteDatabase sqLiteDatabase) { + List tables = getDomainClasses(this.context); + for (Class table : tables) { + sqLiteDatabase.execSQL("DROP TABLE IF EXISTS " + StringUtil.toSQLName(table)); } } diff --git a/library/src/com/orm/SugarRecord.java b/library/src/com/orm/SugarRecord.java index 30eba6ee..dfc80158 100644 --- a/library/src/com/orm/SugarRecord.java +++ b/library/src/com/orm/SugarRecord.java @@ -7,11 +7,9 @@ import android.database.sqlite.SQLiteStatement; import android.text.TextUtils; import android.util.Log; -import com.orm.dsl.Ignore; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.sql.Timestamp; import java.util.*; @@ -19,30 +17,18 @@ public class SugarRecord{ - @Ignore - String tableName = getSqlName(); - protected Long id = null; - public void delete() { - SQLiteDatabase db = getSugarContext().getDatabase().getDB(); - db.delete(this.tableName, "Id=?", new String[]{getId().toString()}); - } - public static > void deleteAll(Class type) { Database db = getSugarContext().getDatabase(); SQLiteDatabase sqLiteDatabase = db.getDB(); - sqLiteDatabase.delete(getTableName(type), null, null); + sqLiteDatabase.delete(StringUtil.toSQLName(type), null, null); } public static > void deleteAll(Class type, String whereClause, String... whereArgs ) { Database db = getSugarContext().getDatabase(); SQLiteDatabase sqLiteDatabase = db.getDB(); - sqLiteDatabase.delete(getTableName(type), whereClause, whereArgs); - } - - public long save() { - return save(getSugarContext().getDatabase().getDB()); + sqLiteDatabase.delete(StringUtil.toSQLName(type), whereClause, whereArgs); } @SuppressWarnings("deprecation") @@ -70,72 +56,12 @@ public static > void saveInTx(Collection objects ) { } - long save(SQLiteDatabase db) { - - List columns = getTableFields(); - ContentValues values = new ContentValues(columns.size()); - for (Field column : columns) { - column.setAccessible(true); - Class columnType = column.getType(); - try { - String columnName = StringUtil.toSQLName(column); - Object columnValue = column.get(this); - if (SugarRecord.class.isAssignableFrom(columnType)) { - values.put(columnName, - (columnValue != null) - ? String.valueOf(((SugarRecord) columnValue).id) - : "0"); - } else { - if (columnType.equals(Short.class) || columnType.equals(short.class)) { - values.put(columnName, (Short) columnValue); - } else if (columnType.equals(Integer.class) || columnType.equals(int.class)) { - values.put(columnName, (Integer) columnValue); - } else if (columnType.equals(Long.class) || columnType.equals(long.class)) { - values.put(columnName, (Long) columnValue); - } else if (columnType.equals(Float.class) || columnType.equals(float.class)) { - values.put(columnName, (Float) columnValue); - } else if (columnType.equals(Double.class) || columnType.equals(double.class)) { - values.put(columnName, (Double) columnValue); - } else if (columnType.equals(Boolean.class) || columnType.equals(boolean.class)) { - values.put(columnName, (Boolean) columnValue); - } else if (Date.class.equals(columnType)) { - try { - values.put(columnName, ((Date) column.get(this)).getTime()); - } catch (NullPointerException e) { - values.put(columnName, (Long) null); - } - } else if (Calendar.class.equals(columnType)) { - try { - values.put(columnName, ((Calendar) column.get(this)).getTimeInMillis()); - } catch (NullPointerException e) { - values.put(columnName, (Long) null); - } - } else { - if (columnValue == null) { - values.putNull(columnName); - } else { - values.put(columnName, String.valueOf(columnValue)); - } - } - } - - } catch (IllegalAccessException e) { - Log.e("Sugar", e.getMessage()); - } - } - - id = db.insertWithOnConflict(getSqlName(), null, values, SQLiteDatabase.CONFLICT_REPLACE); - - Log.i("Sugar", getClass().getSimpleName() + " saved : " + id); - return id; - } - public static > List listAll(Class type) { return find(type, null, null, null, null, null); } public static > T findById(Class type, Long id) { - List list = find( type, "id=?", new String[]{String.valueOf(id)}, null, null, "1"); + List list = find(type, "id=?", new String[]{String.valueOf(id)}, null, null, "1"); if (list.isEmpty()) return null; return list.get(0); } @@ -166,7 +92,7 @@ public static > Iterator findAsIterator(Class typ Database db = getSugarContext().getDatabase(); SQLiteDatabase sqLiteDatabase = db.getDB(); - Cursor c = sqLiteDatabase.query(getTableName(type), null, + Cursor c = sqLiteDatabase.query(StringUtil.toSQLName(type), null, whereClause, whereArgs, groupBy, null, orderBy, limit); return new CursorIterator(type, c); } @@ -209,7 +135,7 @@ public static > List find(Class type, SQLiteDatabase sqLiteDatabase = db.getDB(); T entity; List toRet = new ArrayList(); - Cursor c = sqLiteDatabase.query(getTableName(type), null, + Cursor c = sqLiteDatabase.query(StringUtil.toSQLName(type), null, whereClause, whereArgs, groupBy, null, orderBy, limit); try { while (c.moveToNext()) { @@ -228,22 +154,22 @@ public static > List find(Class type, public static > long count(Class type) { return count(type, null, null, null, null, null); } - + public static > long count(Class type, String whereClause, String[] whereArgs) { return count(type, whereClause, whereArgs, null, null, null); } - + public static > long count(Class type, String whereClause, String[] whereArgs, String groupBy, String orderBy, String limit) { - + Database db = getSugarContext().getDatabase(); SQLiteDatabase sqLiteDatabase = db.getDB(); long toRet = -1; String filter = (!TextUtils.isEmpty(whereClause)) ? " where " + whereClause : ""; - SQLiteStatement sqLiteStatament = sqLiteDatabase.compileStatement("SELECT count(*) FROM " + getTableName(type) + filter); + SQLiteStatement sqLiteStatament = sqLiteDatabase.compileStatement("SELECT count(*) FROM " + StringUtil.toSQLName(type) + filter); if (whereArgs != null) { for (int i = whereArgs.length; i != 0; i--) { @@ -258,14 +184,83 @@ public static > long count(Class type, } finally { sqLiteStatament.close(); } - - return toRet; + + return toRet; + } + + public void delete() { + SQLiteDatabase db = getSugarContext().getDatabase().getDB(); + db.delete(StringUtil.toSQLName(getClass()), "Id=?", new String[]{getId().toString()}); + } + + public long save() { + return save(getSugarContext().getDatabase().getDB()); + } + + long save(SQLiteDatabase db) { + + List columns = SugarDb.getTableFields(getClass()); + ContentValues values = new ContentValues(columns.size()); + for (Field column : columns) { + column.setAccessible(true); + Class columnType = column.getType(); + try { + String columnName = StringUtil.toSQLName(column); + Object columnValue = column.get(this); + if (SugarRecord.class.isAssignableFrom(columnType)) { + values.put(columnName, + (columnValue != null) + ? String.valueOf(((SugarRecord) columnValue).id) + : "0"); + } else { + if (columnType.equals(Short.class) || columnType.equals(short.class)) { + values.put(columnName, (Short) columnValue); + } else if (columnType.equals(Integer.class) || columnType.equals(int.class)) { + values.put(columnName, (Integer) columnValue); + } else if (columnType.equals(Long.class) || columnType.equals(long.class)) { + values.put(columnName, (Long) columnValue); + } else if (columnType.equals(Float.class) || columnType.equals(float.class)) { + values.put(columnName, (Float) columnValue); + } else if (columnType.equals(Double.class) || columnType.equals(double.class)) { + values.put(columnName, (Double) columnValue); + } else if (columnType.equals(Boolean.class) || columnType.equals(boolean.class)) { + values.put(columnName, (Boolean) columnValue); + } else if (Date.class.equals(columnType)) { + try { + values.put(columnName, ((Date) column.get(this)).getTime()); + } catch (NullPointerException e) { + values.put(columnName, (Long) null); + } + } else if (Calendar.class.equals(columnType)) { + try { + values.put(columnName, ((Calendar) column.get(this)).getTimeInMillis()); + } catch (NullPointerException e) { + values.put(columnName, (Long) null); + } + } else { + if (columnValue == null) { + values.putNull(columnName); + } else { + values.put(columnName, String.valueOf(columnValue)); + } + } + } + + } catch (IllegalAccessException e) { + Log.e("Sugar", e.getMessage()); + } + } + + id = db.insertWithOnConflict(StringUtil.toSQLName(getClass()), null, values, SQLiteDatabase.CONFLICT_REPLACE); + + Log.i("Sugar", getClass().getSimpleName() + " saved : " + id); + return id; } @SuppressWarnings("unchecked") void inflate(Cursor cursor) { Map entities = new HashMap(); - List columns = getTableFields(); + List columns = SugarDb.getTableFields(getClass()); for (Field field : columns) { field.setAccessible(true); try { @@ -352,45 +347,6 @@ void inflate(Cursor cursor) { } } - public List getTableFields() { - List fieldList = SugarConfig.getFields(getClass()); - if(fieldList != null) return fieldList; - - Log.d("Sugar", "Fetching properties"); - List typeFields = new ArrayList(); - - getAllFields(typeFields, getClass()); - - List toStore = new ArrayList(); - for (Field field : typeFields) { - if (!field.isAnnotationPresent(Ignore.class) && !Modifier.isStatic(field.getModifiers())&& !Modifier.isTransient(field.getModifiers())) { - toStore.add(field); - } - } - - SugarConfig.setFields(getClass(), toStore); - return toStore; - } - - private static List getAllFields(List fields, Class type) { - Collections.addAll(fields, type.getDeclaredFields()); - - if (type.getSuperclass() != null) { - fields = getAllFields(fields, type.getSuperclass()); - } - - return fields; - } - - public String getSqlName() { - return getTableName(getClass()); - } - - - public static String getTableName(Class type) { - return StringUtil.toSQLNameDefault(type.getSimpleName()); - } - public Long getId() { return id; } diff --git a/library/src/com/orm/dsl/Table.java b/library/src/com/orm/dsl/Table.java new file mode 100644 index 00000000..a801d9d7 --- /dev/null +++ b/library/src/com/orm/dsl/Table.java @@ -0,0 +1,9 @@ +package com.orm.dsl; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Table { + String name(); +} diff --git a/library/src/com/orm/query/Select.java b/library/src/com/orm/query/Select.java index 95688297..8c78bd43 100644 --- a/library/src/com/orm/query/Select.java +++ b/library/src/com/orm/query/Select.java @@ -1,5 +1,6 @@ package com.orm.query; +import com.orm.StringUtil; import com.orm.SugarRecord; import java.util.ArrayList; @@ -130,7 +131,7 @@ String toSql() { sql.append("SELECT * FROM "); - sql.append(SugarRecord.getTableName(this.record) + " "); + sql.append(StringUtil.toSQLName(this.record) + " "); if (whereClause != null) { sql.append("WHERE " + whereClause + " ");