All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.teasoft.beex.android.SqlLibExtForAndroid Maven / Gradle / Ivy

/*
 * Copyright 2020-2022 the original author.All rights reserved.
 * Kingstar([email protected])
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.teasoft.beex.android;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import org.teasoft.bee.app.BeeSqlForApp;
import org.teasoft.bee.osql.SuidType;
import org.teasoft.bee.osql.annotation.customizable.Json;
import org.teasoft.bee.osql.type.TypeHandler;
import org.teasoft.honey.osql.core.ExceptionHelper;
import org.teasoft.honey.osql.core.HoneyConfig;
import org.teasoft.honey.osql.core.HoneyContext;
import org.teasoft.honey.osql.core.HoneyUtil;
import org.teasoft.honey.osql.core.Logger;
import org.teasoft.honey.osql.core.NameTranslateHandle;
import org.teasoft.honey.osql.type.TypeHandlerRegistry;
import org.teasoft.honey.osql.util.AnnoUtil;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;

/**
 * 操作Android环境SQLite数据库接口的实现类.
 * 通常不直接使用这个类,而是通过Suid,SuidRich,MoreTable,MapSuid,PreparedSql间接使用.
 * @author Kingstar
 * @since 1.17
 */
public class SqlLibExtForAndroid implements BeeSqlForApp {

	private SQLiteDatabase database; // 有事务管理.

	public SQLiteDatabase getDatabase() {

		// 从上下文获取
		Object obj = HoneyContext.getCurrentAppDB();
		if (obj != null) return (SQLiteDatabase) obj;

		if (database == null || !database.isOpen()) {
			database = getWritableDB();
			if (database == null) database = BeeSQLiteDatabaseRegistry.getSQLiteDatabase(); // change just return ???
		}//不为null时,则使用原来的
		HoneyContext.setCurrentAppDBIfNeed(database);

		return database;
	}

	public void setDatabase(SQLiteDatabase database) {
		this.database = database;
	}

	private SQLiteDatabase getWritableDB() {
		
		return BeeSQLiteOpenHelper.getWritableDB();
	}

	private static boolean openFieldTypeHandler = HoneyConfig
			.getHoneyConfig().openFieldTypeHandler;

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public  List select(String sql, T entity, String[] selectionArgs) {

		T targetObj = null;
		List rsList = null;
		Map map = null;
		Field field = null;
		String name = null;
		boolean isFirst = true;
		String columnName;
		SQLiteDatabase db = null;
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			int columnCount = cursor.getColumnCount();
			rsList = new ArrayList<>();
			map = new Hashtable<>();

			while (cursor.moveToNext()) {
				targetObj = (T) entity.getClass().newInstance();

				for (int i = 0; i < columnCount; i++) {
					try {
//						columnName = cursor.getColumnName(i + 1);// 会有异常,但提示不明确. Exception: datatype mismatch
						columnName = cursor.getColumnName(i); // 列下标,从0开始
						name = _toFieldName(columnName, entity.getClass());
						if (isFirst) {
							field = entity.getClass().getDeclaredField(name);// 可能会找不到Javabean的字段
							map.put(name, field);
						} else {
							field = map.get(name);
							if (field == null) continue;
						}
					} catch (NoSuchFieldException e) {
						continue;
					}
					field.setAccessible(true);
					Object obj = null;
					boolean isRegHandlerPriority = false;

					try {
						boolean processAsJson = false;
						if (isJoson(field)) {
							obj = cursor.getString(cursor.getColumnIndex(columnName));
							TypeHandler jsonHandler = TypeHandlerRegistry
									.getHandler(Json.class);
							if (jsonHandler != null) {
								obj = jsonHandlerProcess(field, obj, jsonHandler);
								processAsJson = true;
							}
						} else {
							if (openFieldTypeHandler) {
								isRegHandlerPriority = TypeHandlerRegistry
										.isPriorityType(field.getType());
							}
						}

//						if (! processAsJson) obj = cursor.getString(cursor.getColumnIndex(columnName)); 
						if (!processAsJson) obj = getValue(cursor, field, columnName);

						if (isRegHandlerPriority) {
							obj = TypeHandlerRegistry.handlerProcess(field.getType(), obj);
							field.set(targetObj, obj); // 对相应Field设置
						} else {
							field.set(targetObj, obj); // 对相应Field设置
						}
					} catch (IllegalArgumentException e) {
						boolean alreadyProcess = false;
						obj = cursor.getString(cursor.getColumnIndex(columnName));//SQLite in Android get the String first and then transfer
						if (openFieldTypeHandler) {
							Class type = field.getType();
							TypeHandler handler = TypeHandlerRegistry.getHandler(type);
							if (handler != null) {
								try {
									Object newObj = handler.process(type, obj);
									field.set(targetObj, newObj);
									alreadyProcess = true;
								} catch (Exception e2) {
									alreadyProcess = false;
								}
							}
						}
						if (!alreadyProcess) {
							field.set(targetObj, obj);
						}
					}

				}
				rsList.add(targetObj);
				isFirst = false;
			}

		} catch (android.database.SQLException e) {
			Logger.error(e.getMessage(), e);
		} catch (IllegalAccessException e) {
//			hasException = true;
			throw ExceptionHelper.convert(e);
		} catch (InstantiationException e) {
//		hasException = true;
			throw ExceptionHelper.convert(e);
		} finally {
			close(db);
		}

		return rsList;
	}

	private Object getValue(Cursor cursor, Field field, String columnName) {

		int columnIndex = cursor.getColumnIndex(columnName);

		String typeName = field.getType().getName();
		int k = HoneyUtil.getJavaTypeIndex(typeName);
		if ("java.sql.Timestamp".equals(typeName)) { // long???
			k = 1;
		}

		switch (k) {
			case 1:
				return cursor.getString(columnIndex);
			case 2:
				return cursor.getInt(columnIndex);
			case 3:
				return cursor.getLong(columnIndex);
			case 4:
				return cursor.getDouble(columnIndex);
			case 5:
				return cursor.getFloat(columnIndex);
			case 6:
				return cursor.getShort(columnIndex);
//			case 7:
//				return cursor.getByte(columnIndex);
//			case 8:
//				return cursor.getBytes(columnIndex);
//			case 9:
//				return cursor.getBoolean(columnIndex);
			case 10:
				return new BigDecimal(cursor.getString(columnIndex));
//			case 11:
//				return cursor.getDate(columnIndex);
//			case 12:
//				return cursor.getTime(columnIndex);
			case 13:
//				return cursor.getTimestamp(columnIndex);
				return cursor.getLong(columnIndex);
			case 14:
				return cursor.getBlob(columnIndex);
//			case 15:
//				return cursor.getClob(columnIndex);
//			case 16:
//				return cursor.getNClob(columnIndex);
//			case 17:
//				return cursor.getRowId(columnIndex);
//			case 18:
//				return cursor.getSQLXML(columnIndex);

//				19: BigInteger
//				20:char

//				 21:java.util.Date 
//			case 21:	
//				return cursor.getTimestamp(columnIndex);//改动态???
//			case 22:
//				return cursor.getArray(columnIndex);  //java.sql.Array
//			case 23:
//				return cursor.getBinaryStream(columnIndex); //java.io.InputStream
//			case 24:
//				return cursor.getCharacterStream(columnIndex); //java.io.Reader
//			case 25:
//				return cursor.getRef(columnIndex);  //java.sql.Ref	

//			case 27:
//				return cursor.getURL(columnIndex);

//			case 19:
//	        	no  getBigInteger
//			default:
//				return cursor.getObject(columnIndex);

			default:
				return cursor.getString(columnIndex);
		} // end switch

	}

	@Override
	public int modify(String sql, Object[] bindArgs) {
		SuidType regType = HoneyContext.getSuidType();
		if (regType == SuidType.INSERT) {
			long i = insert(sql, bindArgs);
			if (i>0) return 1;
			else return 0;
		} else if (regType == SuidType.UPDATE || regType == SuidType.DELETE) {
			return updateOrDelete(sql, bindArgs);
		} else {
			return execSQL(sql, bindArgs);
		}
	}
	
	private long insert(String sql, Object[] bindArgs) {
		SQLiteDatabase db = null;
		SQLiteStatement st = null;
		long r = 0;
		try {
			db = getDatabase();
			st = db.compileStatement(sql);
			setPreparedValues(st, bindArgs);
			r = st.executeInsert();
		} catch (android.database.SQLException e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db, st);
		}

		return r;
	}
	
	private int updateOrDelete(String sql, Object[] bindArgs) {
		SQLiteDatabase db = null;
		SQLiteStatement st = null;
		int r = 0;
		try {
			db = getDatabase();
			st = db.compileStatement(sql);
			setPreparedValues(st, bindArgs);
			r = st.executeUpdateDelete();
		} catch (android.database.SQLException e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db, st);
		}

		return r;
	}
	
	private int execSQL(String sql, Object[] bindArgs) {
		SQLiteDatabase db = null;
		int r = 0;
		try {
			db = getDatabase();
			db.execSQL(sql, bindArgs);
			r = getAffectRow(db);
		} catch (android.database.SQLException e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}
		return r;
	}

	private int getAffectRow(SQLiteDatabase db) {
		int result;
		SQLiteStatement st = null;
		try {
			// check how many rows been changed
			st = db.compileStatement("select changes()");
			result = (int) st.simpleQueryForLong();
		} catch (android.database.SQLException e) {
			// ignore the exception and just return 1 if it failed
			Logger.error(e.getMessage(), e);
			result = 1; // todo????
		} finally {
			if (st != null) st.close();
//			close(db); //由上层负责
		}
		return result;
	}



	@Override
	public int batchInsert(String sql0, List listBindArgs) {
		SQLiteDatabase db = null;
		SQLiteStatement st = null;
		int total = 0;
		try {
			db = getDatabase();
			st = db.compileStatement(sql0);
			db.beginTransaction();
			long r;

			for (int i = 0; i < listBindArgs.size(); i++) {
				st.clearBindings();
				setPreparedValues(st, listBindArgs.get(i));
				r = st.executeInsert();
				if (r > 0) total++;
			}
			db.setTransactionSuccessful();
		} catch (android.database.SQLException e) {
		   Logger.error(e.getMessage(), e);
		} catch(Exception e2) {
		  Logger.debug(e2.getMessage(), e2);
		}finally {
			try {
				if (db != null) db.endTransaction();	
			} catch (Exception e) {
				Logger.debug(e.getMessage(), e);
			}
			close(db, st);
		}

		return total;
	}

	private void setPreparedValues(SQLiteStatement st, Object[] bindArgs) {
		if (null != bindArgs && bindArgs.length > 0) {
			for (int i = 0; i < bindArgs.length; i++) {
				int objTypeIndex=-1;
				if (bindArgs[i] != null)
					objTypeIndex = HoneyUtil.getJavaTypeIndex(bindArgs[i].getClass().getName());
				_setPreparedValues(st, objTypeIndex, i, bindArgs[i]);
			}
		}
	}

	private void _setPreparedValues(SQLiteStatement st, int objTypeIndex, int i, Object value) {
		if (null == value) {
			st.bindNull(i + 1);
			return;
		}

		switch (objTypeIndex) {
			case 1:
				st.bindString(i + 1, (String) value);
				break;
			case 2:
//				st.bindInt(i + 1, (Integer) value);
				st.bindLong(i + 1, Long.parseLong(value.toString()));
				break;
			case 3:
				st.bindLong(i + 1, (Long) value);
				break;
			case 4:
				st.bindDouble(i + 1, (Double) value);
				break;
			case 5:
//				st.setFloat(i + 1, (Float) value);
				st.bindDouble(i + 1, Double.parseDouble(value.toString()));
				break;
			case 6:
//				st.bindShort(i + 1, (Short) value);
				st.bindLong(i + 1, Long.parseLong(value.toString()));
				break;
			case 7:
//				st.bindByte(i + 1, (Byte) value);
				st.bindLong(i + 1, Long.parseLong(value.toString()));
				break;
			case 8:
//				st.bindBytes(i + 1, (byte[]) value);
				st.bindBlob(i + 1, (byte[]) value);
				break;
//			case 9:
//				st.bindBoolean(i + 1, (Boolean) value); //??
//				break;
			case 10:
//				st.bindBigDecimal(i + 1, (BigDecimal) value); 
				st.bindString(i + 1, ((BigDecimal) value).toPlainString()); // 可以转成字符串?? 数据库里要是字符串类型
				break;
			case 12:
//				st.bindTime(i + 1, (Time) value);  //可以转成字符串 
				st.bindString(i + 1, value.toString());
				break;
			case 13:
//				st.bindTimestamp(i + 1, (Timestamp) value);  //可以转成Long
				st.bindString(i + 1, value.toString());
				break;
//			case 17:
//				st.bindRowId(i + 1, (RowId) value);
//				break;
//			case 18:
//				st.bindSQLXML(i + 1, (SQLXML) value);
//				break;
			case 20:
				st.bindString(i + 1, value.toString());
				break;

			// 如何起效果??? 没能传到这里 改在传过来前,提前转成String
//			case 26:  //Json Annotation
//			{
//				SetParaTypeConvert converter = SetParaTypeConverterRegistry.getConverter(Json.class);
//				if (converter != null) {
//					st.bindString(i + 1, (String) converter.convert(value));
//					break;
//				}
//			}

			default:
				st.bindString(i + 1, (String) value);
				
				
				//要支持自定义的  TODO
		}
	}

	/**
	 * SQL function: max,min,avg,sum,count. 如果统计的结果集为空,除了count返回0,其它都返回空字符.
	 */
	@Override
	public String selectFun(String sql, String[] selectionArgs) {
		SQLiteDatabase db = null;
		String fun = "";
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			if (cursor.moveToNext()) {
				fun = cursor.getString(0);//获取首个元素
				if (fun == null) fun = "";
			} 
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}

		return fun;
	}

	@Override
	public List select(String sql, String[] selectionArgs) {
		SQLiteDatabase db = null;
		List list = new ArrayList<>();
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			list = TransformResultSetForAndroid.toStringsList(cursor);
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}
		return list;
	}

	@Override
	public List> selectMapList(String sql, String[] selectionArgs) {
		SQLiteDatabase db = null;
		List> list = new ArrayList<>();
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			list = TransformResultSetForAndroid.toMapList(cursor);
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}
		return list;
	}

	@Override
	public List> selectMapListWithColumnName(String sql,
			String[] selectionArgs) {
		SQLiteDatabase db = null;
		List> list = new ArrayList<>();
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			list = TransformResultSetForAndroid.toMapListWithColumnName(cursor);
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}
		return list;
	}

	@Override
	@SuppressWarnings("rawtypes")
	public String selectJson(String sql, String[] selectionArgs, Class entityClass) {
		SQLiteDatabase db = null;
		String json = "";
		try {
			db = getDatabase();
			Cursor cursor = db.rawQuery(sql, selectionArgs);
			json = TransformResultSetForAndroid.toJson(cursor, entityClass);
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		} finally {
			close(db);
		}
		return json;
	}

	@Override
	public long insertAndReturnId(String sql, Object[] bindArgs) {
		return insert(sql, bindArgs);
	}

	@SuppressWarnings("rawtypes")
	private static String _toFieldName(String columnName, Class entityClass) {
		return NameTranslateHandle.toFieldName(columnName, entityClass);
	}

	// 检测是否有Json注解
	private boolean isJoson(Field field) {
		return AnnoUtil.isJson(field);
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	private Object jsonHandlerProcess(Field field, Object obj, TypeHandler jsonHandler) {
		if (List.class.isAssignableFrom(field.getType())) {
			Object newOjb[] = new Object[2];
			newOjb[0] = obj;
			newOjb[1] = field;
			obj = jsonHandler.process(field.getType(), newOjb);
		} else {
			obj = jsonHandler.process(field.getType(), obj);
		}
		return obj;
	}

	private void close(SQLiteDatabase db) {
		try {
			if (db != null) {
				if (HoneyContext.getCurrentAppDB() == null) // 当前没有连接时,才删除
					db.close();
			}
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		}
	}

	private void close(SQLiteDatabase db, SQLiteStatement st) {
		try {
			if (st != null) st.close(); // first
			close(db);
		} catch (Exception e) {
			Logger.error(e.getMessage(), e);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy