package org.softeg.sqliteannotations;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/*
* Created by slartus on 25.02.14.
*/
public class BaseDao<T> {
private String mTableName;
private Class<T> tClass;
/**
* The application context.
*/
protected Context mContext;
/**
* Keep the static connection to database.
*/
protected final SQLiteDatabase mDB;
/**
* The default constructor.
*/
public BaseDao(Context context, SQLiteDatabase db, String tableName, Class<T> tClass) {
mContext = context;
mDB = db;
mTableName = tableName.replaceAll("[-/]", "_");
this.tClass = tClass;
}
public void createTable(SQLiteDatabase db) throws Exception {
StringBuffer sql = new StringBuffer("drop table if exists '");
sql.append(getTableName());
sql.append("'; ");
db.execSQL(sql.toString());
sql = new StringBuffer("CREATE TABLE '");
sql.append(getTableName());
sql.append("' (");
sql.append(getPrimaryKeyAnnotation());
for (Field field : getDeclaredFields(tClass)) {
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation == null) continue;
if (fieldEntityAnnotation.isPrimaryKey()) continue;
sql.append(",'");
sql.append(fieldEntityAnnotation.name());
sql.append("' ");
sql.append(fieldEntityAnnotation.type());
}
sql.append(");");
db.execSQL(sql.toString());
}
public boolean isTableExists() {
Cursor cursor = mDB.rawQuery("select DISTINCT tbl_name from sqlite_master where tbl_name = '" + getTableName() + "'", null);
if (cursor != null) {
if (cursor.getCount() > 0) {
cursor.close();
return true;
}
cursor.close();
}
return false;
}
/**
* Get record by specified id.
*
* @param id specified id
* @return the cursor
*/
public Cursor get(String id) {
Cursor cursor;
cursor = mDB.rawQuery(" select * " + " from " + getTableName() + " where _id = ?", null);
return cursor;
}
/**
* Get all data in a specified table.
*
* @return array list keeps all data of table
*/
public Collection<? extends T> getAll() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
if (mDB == null) {
return null;
}
ArrayList<T> items = new ArrayList<>();
Cursor cursor = null;
try {
synchronized (mDB) {
cursor = getAllByCursor();
}
// convert cursor to list items.
if (cursor != null && cursor.getCount() > 0) {
HashMap<Field, Integer> fields = getFieldColumIndexMap(cursor);
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToPosition(i);
T newTObject;
newTObject = tClass.newInstance();
bindObject(newTObject, cursor, fields);
items.add(newTObject);
}
}
} finally {
if (cursor != null)
cursor.close();
}
return items;
}
private HashMap<Field, Integer> getFieldColumIndexMap(Cursor cursor) {
HashMap<Field, Integer> fields = new HashMap<>();
for (Field field : getDeclaredFields(tClass)) {
if (!field.isAccessible())
field.setAccessible(true); // for private variables
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation != null)
fields.put(field, cursor.getColumnIndex(getColumnName(field)));
}
return fields;
}
/**
* Get all data of specified table and return in a cursor.
*
* @return the cursor keeps all data of table
*/
public Cursor getAllByCursor() {
return mDB.query(getTableName(), null, null, null, null, null,
null);
}
/**
* Check whether a specified record exist or not
*
* @param id specified id of record wants to check.
* @return return true if specified data exist.
*/
public boolean isExistence(final String id) {
Cursor cursor = get(id);
if (cursor.getCount() > 0) {
// Close cursor after using
cursor.close();
return true;
}
cursor.close();
return false;
}
/**
* Delete specified record by id.
*
* @param id specified id of record wants to delete.
*/
public void delete(final String id) {
mDB.delete(getTableName(), getPrimaryKeyColumnName() + "='" + id + "'", null);
}
private String getPrimaryKeyColumnName() {
for (Field field : getDeclaredFields(tClass)) {
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation != null) {
String columnName = getColumnName(field);
if (columnName != null) {
Column annotationColumn = field.getAnnotation(Column.class);
if (annotationColumn.isPrimaryKey()) {
return columnName;
}
}
}
}
return "_id";
}
public static Collection<Field> getDeclaredFields(Class<?> clazz) {
Map<String, Field> fields = new HashMap<>();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
if (!fields.containsKey(field.getName())) {
fields.put(field.getName(), field);
}
}
clazz = clazz.getSuperclass();
}
return fields.values();
}
private String getPrimaryKeyAnnotation() throws Exception {
for (Field field : getDeclaredFields(tClass)) {
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation == null) continue;
String columnName = getColumnName(field);
if (columnName == null) continue;
Column annotationColumn = field.getAnnotation(Column.class);
if (!annotationColumn.isPrimaryKey()) continue;
StringBuilder sql = new StringBuilder();
sql.append(columnName);
sql.append(" ");
sql.append(annotationColumn.type());
sql.append(" PRIMARY KEY ");
if (annotationColumn.isAutoincrement())
sql.append("AUTOINCREMENT");
return sql.toString();
}
throw new Exception("Не задан PRIMARY KEY");
}
public long insert(T item) {
if (item != null) {
try {
ContentValues value = getFilledContentValues(item);
return mDB.insertOrThrow(getTableName(), null, value);
} catch (IllegalAccessException e) {
Log.e("insert", e.getMessage());
}
}
return -1;
}
/**
* Delete all data of table.
*/
public final void deleteAll() {
mDB.delete(getTableName(), null, null);
}
/**
* Update data of specified item.
*
* @param object object wants to update
*/
public void update(T object, String id) throws IllegalAccessException {
if (!isTableExists()) return;
ContentValues values = getFilledContentValues(object);
mDB.update(getTableName(), values, getPrimaryKeyColumnName() + "=?", new String[]{id});
}
/**
* Get record by specified id.
*
* @param id specified id
*/
public T getItem(String id) {
Cursor cursor = get(id);
// convert cursor to list items.
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
T newTObject = null;
try {
newTObject = tClass.newInstance();
bindObject(newTObject, cursor, getFieldColumIndexMap(cursor));
} catch (InstantiationException | IllegalAccessException | NoSuchFieldException ignored) {
}
cursor.close();
return newTObject;
}
return null;
}
private void bindObject(T newTObject, Cursor cursor, HashMap<Field, Integer> fieldColumnInds)
throws NoSuchFieldException, IllegalAccessException {
for (Map.Entry<Field, Integer> entry : fieldColumnInds.entrySet()) {
Field field = entry.getKey();
field.set(newTObject, getValueFromCursor(cursor, field, entry.getValue()));
}
}
// Get content from specific types
private Object getValueFromCursor(Cursor cursor, Field field, int columnIndex)
throws IllegalAccessException {
Class<?> fieldType = field.getType();
Object value = null;
if (fieldType.isAssignableFrom(Long.class)
|| fieldType.isAssignableFrom(long.class)) {
value = cursor.getLong(columnIndex);
} else if (fieldType.isAssignableFrom(String.class) ||
fieldType.isAssignableFrom(CharSequence.class)) {
value = cursor.getString(columnIndex);
} else if ((fieldType.isAssignableFrom(Integer.class) || fieldType
.isAssignableFrom(int.class))) {
value = cursor.getInt(columnIndex);
} else if ((fieldType.isAssignableFrom(Byte[].class) || fieldType
.isAssignableFrom(byte[].class))) {
value = cursor.getBlob(columnIndex);
} else if ((fieldType.isAssignableFrom(Double.class) || fieldType
.isAssignableFrom(double.class))) {
value = cursor.getDouble(columnIndex);
} else if ((fieldType.isAssignableFrom(Float.class) || fieldType
.isAssignableFrom(float.class))) {
value = cursor.getFloat(columnIndex);
} else if ((fieldType.isAssignableFrom(Short.class) || fieldType
.isAssignableFrom(short.class))) {
value = cursor.getShort(columnIndex);
} else if (fieldType.isAssignableFrom(Byte.class)
|| fieldType.isAssignableFrom(byte.class)) {
value = (byte) cursor.getShort(columnIndex);
} else if (fieldType.isAssignableFrom(Boolean.class)
|| fieldType.isAssignableFrom(boolean.class)) {
int booleanInteger = cursor.getInt(columnIndex);
value = booleanInteger == 1;
}
return value;
}
public void putInContentValues(ContentValues contentValues, Field field,
Object object) throws IllegalAccessException {
if (!field.isAccessible())
field.setAccessible(true); // for private variables
Object fieldValue = field.get(object);
String key = getColumnName(field);
if (fieldValue instanceof Long) {
contentValues.put(key, Long.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof String || fieldValue instanceof CharSequence) {
contentValues.put(key, fieldValue.toString());
} else if (fieldValue instanceof Integer) {
contentValues.put(key, Integer.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof Float) {
contentValues.put(key, Float.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof Byte) {
contentValues.put(key, Byte.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof Short) {
contentValues.put(key, Short.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof Boolean) {
contentValues.put(key, Boolean.parseBoolean(fieldValue.toString()));
} else if (fieldValue instanceof Double) {
contentValues.put(key, Double.valueOf(fieldValue.toString()));
} else if (fieldValue instanceof Byte[] || fieldValue instanceof byte[]) {
try {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(
outputStream);
objectOutputStream.writeObject(fieldValue);
contentValues.put(key, outputStream.toByteArray());
objectOutputStream.flush();
objectOutputStream.close();
outputStream.flush();
outputStream.close();
} catch (Exception ignored) {
}
}
}
private static String getColumnName(Field field) {
Column annotationColumn = field.getAnnotation(Column.class);
String column = null;
if (annotationColumn != null) {
if (annotationColumn.name().equals("")) {
column = field.getName();
} else {
column = annotationColumn.name();
}
}
return column;
}
private ContentValues getFilledContentValues(Object object)
throws IllegalAccessException {
ContentValues contentValues = new ContentValues();
for (Field field : getDeclaredFields(object.getClass())) {
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation != null) {
if (!fieldEntityAnnotation.isAutoincrement()) {
putInContentValues(contentValues, field, object);
}
}
}
return contentValues;
}
private String[] getColumns() {
boolean isHaveAnyKey = false;
List<String> columnsList = new ArrayList<>();
for (Field field : getDeclaredFields(tClass)) {
Column fieldEntityAnnotation = field.getAnnotation(Column.class);
if (fieldEntityAnnotation != null) {
String columnName = getColumnName(field);
if (columnName != null)
columnsList.add(columnName);
if (fieldEntityAnnotation.isPrimaryKey()) {
isHaveAnyKey = true;
}
}
}
if (!isHaveAnyKey) {
columnsList.add("_id");
}
String[] columnsArray = new String[columnsList.size()];
return columnsList.toArray(columnsArray);
}
@SuppressWarnings("unused")
private Cursor selectCursorFromTable(SQLiteDatabase db, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy) {
try {
String table = getTableName();
String[] columns = getColumns();
Cursor cursor = db.query(table, columns, selection, selectionArgs,
groupBy, having, orderBy);
cursor.moveToFirst();
return cursor;
} catch (Exception e) {
return null;
}
}
public String getTableName() {
return mTableName;
// Table annotationTable = tClass.getAnnotation(Table.class);
// String table = tClass.getSimpleName();
// if (annotationTable != null) {
// if (!annotationTable.name().equals("")) {
// table = annotationTable.name();
// }
// }
// return table;
}
}