@Override public void removeMapKeys( String collection, String name, ColumnField mapField, ArrayList<ColumnField> mapKeys) throws FailedDBOperationException { JSONObject record = null; try { record = lookupEntireRecord(collection, name); } catch (RecordNotFoundException e) { } DatabaseConfig.getLogger().log(Level.FINE, "Record before:{0}", record); if (record == null) { throw new FailedDBOperationException(collection, name, "Record not found."); } if (mapField != null && mapKeys != null) { try { JSONObject json = record.getJSONObject(mapField.getName()); for (int i = 0; i < mapKeys.size(); i++) { String fieldName = mapKeys.get(i).getName(); json.remove(fieldName); } DatabaseConfig.getLogger().log(Level.FINE, "Json after:{0}", json); record.put(mapField.getName(), json); DatabaseConfig.getLogger().log(Level.FINE, "Record after:{0}", record); } catch (JSONException e) { DatabaseConfig.getLogger().log(Level.SEVERE, "Problem updating json: {0}", e.getMessage()); } } getMap(collection).put(name, record); }
@Override public void updateIndividualFields( String collection, String name, ColumnField valuesMapField, ArrayList<ColumnField> valuesMapKeys, ArrayList<Object> valuesMapValues) throws FailedDBOperationException { DatabaseConfig.getLogger() .log(Level.FINE, "Update fields {0}/{1}", new Object[] {name, valuesMapKeys}); JSONObject record; try { record = lookupEntireRecord(collection, name); } catch (RecordNotFoundException e) { throw new FailedDBOperationException(collection, name, "Record not found."); } DatabaseConfig.getLogger().log(Level.FINE, "Record before:{0}", record); if (record == null) { throw new FailedDBOperationException(collection, name); } if (valuesMapField != null && valuesMapKeys != null) { try { JSONObject json = record.getJSONObject(valuesMapField.getName()); for (int i = 0; i < valuesMapKeys.size(); i++) { String fieldName = valuesMapKeys.get(i).getName(); switch (valuesMapKeys.get(i).type()) { case LIST_STRING: JSONDotNotation.putWithDotNotation(json, fieldName, valuesMapValues.get(i)); // json.put(fieldName, valuesMapValues.get(i)); break; case USER_JSON: JSONDotNotation.putWithDotNotation( json, fieldName, JSONParse(valuesMapValues.get(i))); // json.put(fieldName, JSONParse(valuesMapValues.get(i))); break; default: DatabaseConfig.getLogger() .log(Level.WARNING, "Ignoring unknown format: {0}", valuesMapKeys.get(i).type()); break; } } DatabaseConfig.getLogger().log(Level.FINE, "Json after:{0}", json); record.put(valuesMapField.getName(), json); DatabaseConfig.getLogger().log(Level.FINE, "Record after:{0}", record); } catch (JSONException e) { DatabaseConfig.getLogger().log(Level.SEVERE, "Problem updating json: {0}", e.getMessage()); } } getMap(collection).put(name, record); }
/** * 解析符合fastDB的 Annotation 注解对象 注:该方法是升级版,支持继承注解属性获取;采用的是 getMethods 获取继承的所有公共方法,然后解析 getter * 方法获得字段属性(这就要求getter方法和字段属性必须是严格的生成关系)。 * * @param obj 注解对象 * @param isPersistenced 对象是否已经被持久化了, false -- 用在 insert 时; true -- 用在 update 时 * @return Persistence对象 */ public static Persistence parsePersistence(Object obj, boolean isPersistenced) { Class<?> clz = obj.getClass(); // 只有通过 getMethods 方法才能获取到继承自父类的私有字段属性 Method[] methods = clz.getMethods(); // 字段是否存在,用来递归解析注解字段 boolean isFieldExist = true; // 用于内部强制异常时,中断catch;此处用在下面的 sequence 判断 boolean isBreak = false; // 主键字段 // PrimaryField p_field = null; // 普通字段 ColumnField n_field = null; String col_name = null; Object col_val = null; Persistence persistence = new Persistence(); persistence.setTableName(getTableName(clz)); for (Method m : methods) { /* 每次字段查找都要从当前类开始,然后再递归父类。 因为 getMethods()返回的数组中的元素没有排序,也没有任何特定的顺序,有可能当前类的某(些)字段被放置到了父类属性的后面, 而后面的递归父类操作改变了 clz 的对象,这样一来会造成这些字段被丢弃; 所以每次查找开始都要将 clz 对象重置为当前对象。 */ clz = obj.getClass(); String m_name = m.getName(); // 只解析getter方法,对于Boolean类型,其getter方法可能是 isAbc if (!m_name.startsWith("get") && !m_name.startsWith("is")) { continue; } // getter 方法无参数 if (m.getParameterTypes().length > 0) { continue; } // Java注解只支持基本数据类型 if (!ColumnType.isPrimitiveClass(m.getReturnType())) { continue; } m_name = lowerFirst(m_name.startsWith("get") ? m_name.substring(3) : m_name.substring(2)); // 如果当前类找不到Field定义,则递归到其父类中寻找,以此进行下去 Field f; Column col; do { try { // 这里会产生后面的异常:如果字段是父类中继承过来的,则在当前类getDeclaredField会产生异常 f = clz.getDeclaredField(m_name); col = f.getAnnotation(Column.class); // 如果该字段定义了注解,则解析;如果没有定义注解,则也不会到父类中查找 if (null != col) { col_name = col.name(); col_val = m.invoke(obj, new Object[] {}); // 列名 @Column(name='') 为空,则使用属性名替代 if (null == col_name || col_name.trim().length() == 0) { col_name = f.getName(); } // 如果是主键 if (col.primaryKey()) { // 如果对象未被持久化 并且是 SEQUENCE 生成方式 if (!isPersistenced && col.generatorType() == GeneratorType.SEQUENCE) { // 对于SEQUENCE 生成方式的主键,必须指定 SEQUENCE 名称 if (null == col.sequence() || col.sequence().trim().length() == 0) { isBreak = true; throw new IllegalArgumentException( "The " + clz.getName() + "[" + f.getName() + "] Annotation @Column(isPrimaryKey=true, generatorType=GeneratorType.SEQUENCE, sequence='...'), but the sequence name is empty!"); } // sequence 方式主键的值是 seqname.NEXTVAL col_val = col.sequence() + ".NEXTVAL"; } // 创建主键字段 // 扩充了ColumnField,使用 ColumnField替代 /*p_field = new PrimaryField(); p_field.setName( col_name ); p_field.setValue( col_val ); p_field.setGeneratorType( col.generatorType() ); p_field.setType(f.getType()); persistence.addPrimaryField( p_field );*/ } // 创建字段 n_field = new ColumnField(); n_field.setName(col_name); n_field.setValue(col_val); n_field.setType(f.getType()); n_field.setPrimaryKey(col.primaryKey()); n_field.setGeneratorType(col.generatorType()); persistence.addColumnField(n_field); } isFieldExist = true; } catch (Exception e) { // 内部强制抛出异常 if (isBreak) { e.printStackTrace(); return null; } isFieldExist = false; // 如果当前类没有找到,则到其父类中查找 clz = clz.getSuperclass(); // 父类不存在或是Object基类,则结束下次递归操作 if (null == clz || "java.lang.Object".equals(clz.getName())) { isFieldExist = true; } } } while (!isFieldExist); n_field = null; } return persistence; }
/** * 根据已经持久化的注解对象创建 Update SQL 语句 * * @param bean 已经持久化的注解对象 * @param updateFields 给定待更新的字段集合,如果为null,则更新全部 * @return object[0] -- 带占位符 ? 的Update SQL;<br> * object[1] -- 占位符对应的参数值 */ public static Object[] createUpdateSQL(Object bean, String[] updateFields) { if (null == bean) { return null; } // 采用新的解析方式,用于支持注解继承 Persistence p = parsePersistence(bean, true); Map<String, String> mapping = getFieldAnnotationMapping(bean.getClass()); if (null == p || null == p.getTableName()) { return null; } Object[] oo = new Object[2]; StringBuilder sql_buf_1 = new StringBuilder(); StringBuilder sql_buf_2 = new StringBuilder(); sql_buf_1.append("UPDATE "); sql_buf_1.append(p.getTableName()); sql_buf_1.append(" SET "); sql_buf_2.append(" WHERE "); List<Object> valList = new LinkedList<Object>(); List<ColumnField> col_fields = p.getColumnFields(); // 普通列 for (ColumnField cf : col_fields) { /*if( cf.isPrimaryKey() ) { continue; }*/ // 判断Bean的属性,而不是@Column对应的数据表列名 if (withinUpdateFields(mapping.get(cf.getName()), updateFields)) { sql_buf_1.append(cf.getName()); sql_buf_1.append(" = ?, "); valList.add(cf.getValue()); } } // 主键列 for (ColumnField pf : col_fields) { if (!pf.isPrimaryKey()) { continue; } sql_buf_2.append(pf.getName()); sql_buf_2.append(" = ? AND "); valList.add(pf.getValue()); } String sql1 = sql_buf_1.toString(); String sql2 = sql_buf_2.toString(); if (sql1.lastIndexOf(",") != -1) { sql1 = sql1.substring(0, sql1.lastIndexOf(",")); } if (sql2.lastIndexOf("AND") != -1) { sql2 = sql2.substring(0, sql2.lastIndexOf("AND")); } oo[0] = sql1 + sql2; oo[1] = valList.toArray(); sql_buf_1 = null; sql_buf_2 = null; valList.clear(); valList = null; p.clear(); p = null; return oo; }
/** * 根据未持久化的注解对象创建 Insert SQL 语句 * * @param bean 注解对象 * @return object[0] -- 带占位符 ? 的 Insert SQL; <br> * object[1] -- 占位符对应的参数值 */ public static Object[] createInsertSQL(Object bean) { if (bean == null) { return null; } // 采用新的解析方式,用于支持注解继承 Persistence p = parsePersistence(bean, false); if (null == p || null == p.getTableName()) { return null; } Object[] oo = new Object[2]; StringBuilder sql_buf_1 = new StringBuilder(); StringBuilder sql_buf_2 = new StringBuilder(); sql_buf_1.append("INSERT INTO "); sql_buf_1.append(p.getTableName()); sql_buf_1.append("("); sql_buf_2.append(" VALUES("); List<Object> valList = new LinkedList<Object>(); List<ColumnField> col_fields = p.getColumnFields(); // 主键列 for (ColumnField pf : col_fields) { if (!pf.isPrimaryKey()) { continue; } if (pf.getGeneratorType() == GeneratorType.SEQUENCE) { sql_buf_1.append(pf.getName()); sql_buf_1.append(", "); sql_buf_2.append(pf.getValue()); sql_buf_2.append(", "); } else if (pf.getGeneratorType() == GeneratorType.ASSIGN) { sql_buf_1.append(pf.getName()); sql_buf_1.append(", "); sql_buf_2.append("?, "); valList.add(pf.getValue()); } } // 普通列 for (ColumnField cf : col_fields) { if (cf.isPrimaryKey()) { continue; } sql_buf_1.append(cf.getName()); sql_buf_1.append(", "); sql_buf_2.append("?, "); valList.add(cf.getValue()); } String sql1 = sql_buf_1.toString(); String sql2 = sql_buf_2.toString(); if (sql1.lastIndexOf(",") != -1) { sql1 = sql1.substring(0, sql1.lastIndexOf(",")) + ")"; } if (sql2.lastIndexOf(",") != -1) { sql2 = sql2.substring(0, sql2.lastIndexOf(",")) + ")"; } oo[0] = sql1 + sql2; oo[1] = valList.toArray(); sql_buf_1 = null; sql_buf_2 = null; valList.clear(); valList = null; p.clear(); p = null; return oo; }
@Override public HashMap<ColumnField, Object> lookupSomeFields( String collection, String name, ColumnField nameField, ColumnField valuesMapField, ArrayList<ColumnField> valuesMapKeys) throws RecordNotFoundException, FailedDBOperationException { JSONObject record = lookupEntireRecord(collection, name); // DatabaseConfig.getLogger().log(Level.FINE, "Full record " + record.toString()); HashMap<ColumnField, Object> hashMap = new HashMap<>(); hashMap.put(nameField, name); if (valuesMapField != null && valuesMapKeys != null) { try { JSONObject readValuesMap = record.getJSONObject(valuesMapField.getName()); // DatabaseConfig.getLogger().log(Level.FINE, "Read valuesMap " + // readValuesMap.toString()); ValuesMap valuesMapOut = new ValuesMap(); for (int i = 0; i < valuesMapKeys.size(); i++) { String userKey = valuesMapKeys.get(i).getName(); if (JSONDotNotation.containsFieldDotNotation(userKey, readValuesMap) == false) { // DatabaseConfig.getLogger().fine("valuesMap doesn't contain " + userKey); continue; } try { switch (valuesMapKeys.get(i).type()) { case USER_JSON: Object value = JSONDotNotation.getWithDotNotation(userKey, readValuesMap); DatabaseConfig.getLogger() .log(Level.FINE, "Object is {0}", new Object[] {value.toString()}); valuesMapOut.put(userKey, value); break; case LIST_STRING: valuesMapOut.putAsArray( userKey, JSONUtils.JSONArrayToResultValue( new JSONArray( JSONDotNotation.getWithDotNotation(userKey, readValuesMap) .toString()))); break; default: DatabaseConfig.getLogger() .log( Level.SEVERE, "ERROR: Error: User keys field {0} is not a known type:{1}", new Object[] {userKey, valuesMapKeys.get(i).type()}); break; } } catch (JSONException e) { DatabaseConfig.getLogger().log(Level.SEVERE, "Error parsing json: {0}", e.getMessage()); } } hashMap.put(valuesMapField, valuesMapOut); } catch (JSONException e) { DatabaseConfig.getLogger() .log(Level.SEVERE, "Problem getting values map: {0}", e.getMessage()); } } return hashMap; }