Fixed some bugs in DBBean and added a Junit TC for it

This commit is contained in:
Ziver Koc 2017-02-10 18:09:07 +01:00
parent 70189fddfe
commit 1aedfb52b7
4 changed files with 299 additions and 80 deletions

View file

@ -144,90 +144,98 @@ public abstract class DBBean {
Class<? extends DBBean> c = this.getClass(); Class<? extends DBBean> c = this.getClass();
DBBeanConfig config = DBBeanConfig.getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
try { try {
Long id = this.getId(); // Generate the SQL
// Generate the SQL StringBuilder query = new StringBuilder();
StringBuilder query = new StringBuilder(); if (this.id == null) {
if( id == null ) { query.append("INSERT INTO ").append(config.tableName).append(' ');
query.append("INSERT INTO ").append( config.tableName ); StringBuilder sqlCols = new StringBuilder();
query.append( " (" ); StringBuilder sqlValues = new StringBuilder();
for( Field field : config.fields ){ for (Field field : config.fields) {
if( !List.class.isAssignableFrom(field.getType()) ){ if (!List.class.isAssignableFrom(field.getType())) {
query.append(" "); if (sqlCols.length() == 0)
query.append(DBBeanConfig.getFieldName(field)); sqlCols.append("(");
query.append(","); else sqlCols.append(", ");
sqlCols.append(DBBeanConfig.getFieldName(field));
if (sqlValues.length() == 0)
sqlValues.append("VALUES(");
else sqlValues.append(", ");
sqlValues.append("?");
} }
} }
if(query.charAt(query.length()-1) == ',') if (sqlCols.length() > 0) {
query.deleteCharAt(query.length()-1); query.append(sqlCols).append(") ");
query.append( ") VALUES(" ); query.append(sqlValues).append(") ");
for( Field field : config.fields ){ } else
query.append( "?," ); query.append("DEFAULT VALUES");
} } else {
if(query.charAt(query.length()-1) == ',') query.append("UPDATE ").append(config.tableName).append(' ');
query.deleteCharAt(query.length()-1); StringBuilder sqlSets = new StringBuilder();
query.append( ")" ); for (Field field : config.fields) {
} if (!List.class.isAssignableFrom(field.getType())) {
else{ if (sqlSets.length() > 0)
query.append("UPDATE ").append( config.tableName ); sqlSets.append(", ");
query.append( " SET" ); sqlSets.append(DBBeanConfig.getFieldName(field));
for( Field field : config.fields ){ sqlSets.append("=?");
if( !List.class.isAssignableFrom(field.getType()) ){
query.append(" ");
query.append(DBBeanConfig.getFieldName(field));
query.append("=?,");
} }
} }
if(query.charAt(query.length()-1) == ',') if (sqlSets.length() > 0) {
query.deleteCharAt(query.length()-1); query.append("SET ").append(sqlSets);
query.append(" WHERE ").append(config.idColumn).append("=?"); query.append("WHERE ").append(config.idColumn).append("=?");
} else
query = null; // Class has no fields that needs updating
} }
String sql = query.toString(); // Check if we have a valid query to run, skip otherwise
logger.finest("Save Bean("+c.getName()+", id: "+this.getId()+") query: "+ sql); if (query != null) {
PreparedStatement stmt = db.getPreparedStatement( sql ); String sql = query.toString();
// Put in the variables in the SQL logger.finest("Save Bean(" + c.getName() + ", id: " + this.getId() + ") query: " + sql);
int index = 1; PreparedStatement stmt = db.getPreparedStatement(sql);
for(Field field : config.fields){ // Put in the variables in the SQL
int index = 1;
for (Field field : config.fields) {
// Another DBBean class
if (DBBean.class.isAssignableFrom(field.getType())) {
DBBean subObj = (DBBean) getFieldValue(field);
if (subObj != null) {
if (recursive || subObj.getId() == null)
subObj.save(db);
stmt.setObject(index, subObj.getId());
} else
stmt.setObject(index, null);
index++;
}
// A list of DBBeans
else if (List.class.isAssignableFrom(field.getType()) &&
field.getAnnotation(DBLinkTable.class) != null) {
// Do stuff later
}
// Normal field
else {
Object value = getFieldValue(field);
stmt.setObject(index, value);
index++;
}
}
if (this.id != null)
stmt.setObject(index, this.id);
// Another DBBean class // Execute the SQL
if( DBBean.class.isAssignableFrom( field.getType() )){ DBConnection.exec(stmt);
DBBean subObj = (DBBean)getFieldValue(field); if (this.id == null) {
if(subObj != null){ this.id = db.getLastInsertID(stmt);
if( recursive || subObj.getId() == null ) // as this is a new object so add it to the cache
subObj.save(db); DBBeanSQLResultHandler.cacheDBBean(this);
stmt.setObject(index, subObj.getId() ); }
}
else
stmt.setObject(index, null);
index++;
}
// A list of DBBeans
else if( List.class.isAssignableFrom( field.getType() ) &&
field.getAnnotation( DBLinkTable.class ) != null){
// Do stuff later
}
// Normal field
else{
Object value = getFieldValue(field);
stmt.setObject(index, value);
index++;
}
}
if( id != null )
stmt.setObject(index, id);
// Execute the SQL
DBConnection.exec(stmt);
if( id == null ) {
this.id = db.getLastInsertID(stmt);
// as this is a new object so add it to the cache
DBBeanSQLResultHandler.cacheDBBean(this);
} }
// Save the list, after we get the object id // Save sub beans, after we get the parent object id
for(Field field : config.fields){ for(Field field : config.fields){
if( List.class.isAssignableFrom( field.getType() ) && if( List.class.isAssignableFrom( field.getType() ) &&
field.getAnnotation( DBLinkTable.class ) != null){ field.getAnnotation( DBLinkTable.class ) != null){
if (this.id == null)
throw new SQLException("Unknown parent object id");
List<DBBean> list = (List<DBBean>)getFieldValue(field); List<DBBean> list = (List<DBBean>)getFieldValue(field);
if( list != null ){ if( list != null ){
DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class ); DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class );
@ -250,14 +258,14 @@ public abstract class DBBean {
subIdCol = subConfig.idColumn; subIdCol = subConfig.idColumn;
} }
// Save links in link table // Save links in link table
sql = ""; String sql;
if( subTable.equals(subConfig.tableName) ) if( subTable.equals(subConfig.tableName) )
sql = "UPDATE "+subTable+" SET "+idCol+"=? WHERE "+subIdCol+"=?"; sql = "UPDATE "+subTable+" SET "+idCol+"=? WHERE "+subIdCol+"=?";
else else
sql = "REPLACE INTO "+subTable+" SET "+idCol+"=?, "+subIdCol+"=?"; sql = "REPLACE INTO "+subTable+" SET "+idCol+"=?, "+subIdCol+"=?";
logger.finest("Save Bean("+c.getName()+", id: "+subObj.getId()+") query: "+sql); logger.finest("Save Bean("+c.getName()+", id: "+subObj.getId()+") query: "+sql);
PreparedStatement subStmt = db.getPreparedStatement( sql ); PreparedStatement subStmt = db.getPreparedStatement( sql );
subStmt.setLong(1, this.getId() ); subStmt.setLong(1, this.id );
subStmt.setLong(2, subObj.getId() ); subStmt.setLong(2, subObj.getId() );
DBConnection.exec(subStmt); DBConnection.exec(subStmt);
} }
@ -348,13 +356,13 @@ public abstract class DBBean {
// ID // ID
query.append(" ").append(config.idColumn).append(" "); query.append(" ").append(config.idColumn).append(" ");
query.append( classToDBName( Long.class ) ); query.append( classToColType( Long.class ) );
query.append(" PRIMARY KEY AUTO_INCREMENT, "); query.append(" PRIMARY KEY AUTO_INCREMENT, ");
for( Field field : config.fields ){ for( Field field : config.fields ){
query.append(" "); query.append(" ");
query.append( DBBeanConfig.getFieldName(field) ); query.append( DBBeanConfig.getFieldName(field) );
query.append( classToDBName(c) ); query.append( classToColType(c) );
query.append(", "); query.append(", ");
} }
query.delete( query.length()-2, query.length()); query.delete( query.length()-2, query.length());
@ -367,7 +375,7 @@ public abstract class DBBean {
DBConnection.exec(stmt); DBConnection.exec(stmt);
} }
private static String classToDBName(Class<?> c){ private static String classToColType(Class<?> c){
if( c == String.class) return "CLOB"; // TEXT if( c == String.class) return "CLOB"; // TEXT
else if(c == Short.class) return "SMALLINT"; else if(c == Short.class) return "SMALLINT";
else if(c == short.class) return "SMALLINT"; else if(c == short.class) return "SMALLINT";
@ -387,7 +395,7 @@ public abstract class DBBean {
else if(c == byte.class) return "BINARY(1)"; else if(c == byte.class) return "BINARY(1)";
else if(c == Timestamp.class) return "DATETIME"; else if(c == Timestamp.class) return "DATETIME";
else if(DBBean.class.isAssignableFrom(c)) else if(DBBean.class.isAssignableFrom(c))
return classToDBName(Long.class); return classToColType(Long.class);
return null; return null;
} }

View file

@ -67,7 +67,7 @@ class DBBeanConfig{
* Caches the fields * Caches the fields
*/ */
private static void initBeanConfig(Class<? extends DBBean> c){ private static void initBeanConfig(Class<? extends DBBean> c){
logger.fine("Initiating new BeanConfig( "+c.getName()+" )"); //logger.fine("Initiating new BeanConfig( "+c.getName()+" )");
DBBeanConfig config = new DBBeanConfig(); DBBeanConfig config = new DBBeanConfig();
// Find the table name // Find the table name
DBBean.DBTable tableAnn = c.getAnnotation(DBBean.DBTable.class); DBBean.DBTable tableAnn = c.getAnnotation(DBBean.DBTable.class);

View file

@ -107,4 +107,12 @@ public abstract class DBBeanObjectDSO<T> extends DBBean{
public Configurator<T> getObjectConfigurator(){ public Configurator<T> getObjectConfigurator(){
return new Configurator<>(cachedObj); return new Configurator<>(cachedObj);
} }
public String toString(){
Object obj = getObject();
if (obj != null)
return obj.toString();
return "null (DSO: "+ super.toString() +")";
}
} }

View file

@ -0,0 +1,203 @@
package zutil.db.bean;
import org.junit.BeforeClass;
import org.junit.Test;
import zutil.db.DBConnection;
import zutil.db.handler.SimpleSQLResult;
import zutil.log.CompactLogFormatter;
import zutil.log.LogUtil;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import static org.junit.Assert.*;
/**
*
*/
public class DBBeanSaveTest {
private DBConnection db = new DBConnection(DBConnection.DBMS.SQLite, ":memory:");
public DBBeanSaveTest() throws Exception {}
@BeforeClass
public static void init(){
LogUtil.setGlobalFormatter(new CompactLogFormatter());
LogUtil.setGlobalLevel(Level.ALL);
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
private static class SimpleTestClass extends DBBean{
int intField;
String strField;
}
@Test
public void simpleClassCreate() throws SQLException {
db.exec("CREATE TABLE SimpleTestClass (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"intField INTEGER, " +
"strField TEXT);");
SimpleTestClass obj = new SimpleTestClass();
obj.intField = 1234;
obj.strField = "helloworld";
obj.save(db);
assertEquals(1234,
getColumnValue(db, "SimpleTestClass", "intField"));
assertEquals("helloworld",
getColumnValue(db, "SimpleTestClass", "strField"));
}
@Test
public void simpleClassUpdate() throws SQLException {
db.exec("CREATE TABLE SimpleTestClass (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"intField INTEGER, " +
"strField TEXT);");
SimpleTestClass obj = new SimpleTestClass();
obj.intField = 1234;
obj.strField = "helloworld";
obj.save(db);
obj.intField = 1337;
obj.strField = "monkey";
obj.save(db);
assertEquals(1337,
getColumnValue(db, "SimpleTestClass", "intField"));
assertEquals("monkey",
getColumnValue(db, "SimpleTestClass", "strField"));
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
@DBBean.DBTable("aliasTable")
private static class AliasFieldsTestClass extends DBBean{
@DBColumn("aliasIntField")
int intField;
@DBColumn("aliasStrField")
String strField;
}
@Test
public void aliasFieldsCreate() throws SQLException {
db.exec("CREATE TABLE aliasTable (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"aliasIntField INTEGER, " +
"aliasStrField TEXT);");
AliasFieldsTestClass obj = new AliasFieldsTestClass();
obj.intField = 1234;
obj.strField = "helloworld";
obj.save(db);
assertEquals(1234,
getColumnValue(db, "aliasTable", "aliasIntField"));
assertEquals("helloworld",
getColumnValue(db, "aliasTable", "aliasStrField"));
}
@Test
public void aliasFieldsUpdate() throws SQLException {
db.exec("CREATE TABLE aliasTable (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"aliasIntField INTEGER, " +
"aliasStrField TEXT);");
AliasFieldsTestClass obj = new AliasFieldsTestClass();
obj.intField = 1234;
obj.strField = "helloworld";
obj.save(db);
obj.intField = 1337;
obj.strField = "monkey";
obj.save(db);
assertEquals(1337,
getColumnValue(db, "aliasTable", "aliasIntField"));
assertEquals("monkey",
getColumnValue(db, "aliasTable", "aliasStrField"));
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
@DBBean.DBTable("parent")
private static class ParentTestClass extends DBBean{
@DBLinkTable(table = "subobject", idColumn = "parent_id",beanClass = SubObjectTestClass.class)
List<SubObjectTestClass> subobjs = new ArrayList<>();
}
@DBBean.DBTable("subobject")
private static class SubObjectTestClass extends DBBean{
int intField;
}
@Test
public void subObjectCreate() throws SQLException {
db.exec("CREATE TABLE parent (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);");
db.exec("CREATE TABLE subobject (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"parent_id INTEGER, " +
"intField INTEGER);");
ParentTestClass obj = new ParentTestClass();
SubObjectTestClass subObj = new SubObjectTestClass();
subObj.intField = 1337;
obj.subobjs.add(subObj);
obj.save(db);
assertEquals(1337,
getColumnValue(db, "subobject", "intField"));
assertEquals(1,
getColumnValue(db, "subobject", "parent_id"));
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
@DBBean.DBTable("parent")
private static class ParentLinkTestClass extends DBBean{
@DBLinkTable(table = "link", idColumn = "parent_id",beanClass = SubObjectTestClass.class)
List<SubObjectTestClass> subobjs = new ArrayList<>();
}
@Test
public void subLinkObjectCreate() throws SQLException {
db.exec("CREATE TABLE parent (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT);");
db.exec("CREATE TABLE link (" +
"parent_id INTEGER, " +
"id INTEGER);");
db.exec("CREATE TABLE subobject (" +
"id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, " +
"parent_id INTEGER, " +
"intField INTEGER);");
ParentTestClass obj = new ParentTestClass();
SubObjectTestClass subObj = new SubObjectTestClass();
subObj.intField = 1337;
obj.subobjs.add(subObj);
obj.save(db);
assertEquals(1,
getColumnValue(db, "link", "parent_id"));
assertEquals(1,
getColumnValue(db, "link", "id"));
assertEquals(1337,
getColumnValue(db, "subobject", "intField"));
}
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
public static Object getColumnValue(DBConnection db, String table, String column) throws SQLException {
return db.exec("SELECT "+column+" FROM "+table, new SimpleSQLResult<>());
}
}