Refactored DBBean and added DBColumn annotation

This commit is contained in:
Ziver Koc 2015-12-15 23:53:35 +01:00
parent 431d238c19
commit 74e8c4aa68
4 changed files with 124 additions and 97 deletions

BIN
Zutil.jar

Binary file not shown.

View file

@ -38,8 +38,6 @@ import java.math.BigInteger;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Timestamp; import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.logging.Level; import java.util.logging.Level;
@ -87,104 +85,41 @@ public abstract class DBBean {
} }
/** /**
* Sets the name of the table that links different DBBeans together * Can be used if the column name is different from the field name.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface DBColumn {
/** This is the name of the column in the database for the specified field. SQL rules apply, should not contain any strange characters or spaces **/
String value();
}
/**
* Should be used for fields with lists of DBBeans.
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) @Target(ElementType.FIELD)
public @interface DBLinkTable { public @interface DBLinkTable {
/** The name of the Link table, SQL rules apply should not contain any strange characters or spaces */ /** The name of the Link table, SQL rules apply, should not contain any strange characters or spaces */
String table(); String table();
/** The class of the linked bean */ /** The class of the linked bean */
Class<? extends DBBean> beanClass(); Class<? extends DBBean> beanClass();
/** The name of the column that contains the main objects id, SQL rules apply should not contain any strange characters or spaces */ /** The name of the column that contains the main objects id, SQL rules apply, should not contain any strange characters or spaces */
String idColumn() default ""; String idColumn() default "";
} }
/**
* A Class that contains information about a bean
*/
protected static class DBBeanConfig{
/** The name of the table in the DB **/
protected String tableName;
/** The name of the id column **/
protected String idColumn;
/** All the fields in the bean **/
protected ArrayList<Field> fields;
protected DBBeanConfig(){
fields = new ArrayList<Field>();
}
}
/** This is a cache of all the initialized beans */
private static HashMap<String,DBBeanConfig> beanConfigs = new HashMap<String,DBBeanConfig>();
/** This value is for preventing recursive loops when saving */ /** This value is for preventing recursive loops when saving */
protected boolean processing_save; protected boolean processing_save;
/** This value is for preventing recursive loops when updating */ /** This value is for preventing recursive loops when updating */
protected boolean processing_update; protected boolean processing_update;
protected DBBean(){ protected DBBean(){
if( !beanConfigs.containsKey( this.getClass() ) ) DBBeanConfig.getBeanConfig(this.getClass());
initBeanConfig( this.getClass() );
processing_save = false; processing_save = false;
processing_update = false; processing_update = false;
} }
/**
* @return all the fields except the ID field
*/
public static ArrayList<Field> getFields(Class<? extends DBBean> c){
if( !beanConfigs.containsKey( c.getName() ) )
initBeanConfig( c );
return beanConfigs.get( c.getName() ).fields;
}
/**
* @return the configuration object for the specified class
*/
protected static DBBeanConfig getBeanConfig(Class<? extends DBBean> c){
if( !beanConfigs.containsKey( c.getName() ) )
initBeanConfig( c );
return beanConfigs.get( c.getName() );
}
/**
* Caches the fields
*/
private static void initBeanConfig(Class<? extends DBBean> c){
logger.fine("Initiating new DBBeanConfig( "+c.getName()+" )");
DBBeanConfig config = new DBBeanConfig();
// Find the table name
DBTable tableAnn = c.getAnnotation(DBTable.class);
if( tableAnn != null ){
config.tableName = tableAnn.value();
config.idColumn = tableAnn.idColumn();
}
else{
config.tableName = c.getSimpleName();
config.idColumn = "id";
}
// Add the fields in the bean and all the super classes fields
for(Class<?> cc = c; cc != DBBean.class ;cc = cc.getSuperclass()){
Field[] fields = cc.getDeclaredFields();
for( Field field : fields ){
int mod = field.getModifiers();
if( !Modifier.isTransient( mod ) &&
!Modifier.isAbstract( mod ) &&
!Modifier.isFinal( mod ) &&
!Modifier.isStatic( mod ) &&
!Modifier.isInterface( mod ) &&
!Modifier.isNative( mod ) &&
!config.fields.contains( field )){
config.fields.add( field );
}
}
if( tableAnn == null || !tableAnn.superBean() )
break;
}
beanConfigs.put(c.getName(), config);
}
/** /**
* Saves the object and all the sub objects to the DB * Saves the object and all the sub objects to the DB
@ -207,7 +142,7 @@ public abstract class DBBean {
return; return;
processing_save = true; processing_save = true;
Class<? extends DBBean> c = this.getClass(); Class<? extends DBBean> c = this.getClass();
DBBeanConfig config = getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
try { try {
Long id = this.getId(); Long id = this.getId();
// Generate the SQL // Generate the SQL
@ -218,7 +153,7 @@ public abstract class DBBean {
for( Field field : config.fields ){ for( Field field : config.fields ){
if( !List.class.isAssignableFrom(field.getType()) ){ if( !List.class.isAssignableFrom(field.getType()) ){
query.append(" "); query.append(" ");
query.append(field.getName()); query.append(DBBeanConfig.getFieldName(field));
query.append(","); query.append(",");
} }
} }
@ -238,7 +173,7 @@ public abstract class DBBean {
for( Field field : config.fields ){ for( Field field : config.fields ){
if( !List.class.isAssignableFrom(field.getType()) ){ if( !List.class.isAssignableFrom(field.getType()) ){
query.append(" "); query.append(" ");
query.append(field.getName()); query.append(DBBeanConfig.getFieldName(field));
query.append("=?,"); query.append("=?,");
} }
} }
@ -308,7 +243,7 @@ public abstract class DBBean {
} }
// Get the Sub object configuration // Get the Sub object configuration
if(subConfig == null){ if(subConfig == null){
subConfig = getBeanConfig( subobj.getClass() ); subConfig = DBBeanConfig.getBeanConfig( subobj.getClass() );
sub_idcol = subConfig.idColumn; sub_idcol = subConfig.idColumn;
} }
// Save links in link table // Save links in link table
@ -342,7 +277,7 @@ public abstract class DBBean {
*/ */
public void delete(DBConnection db) throws SQLException{ public void delete(DBConnection db) throws SQLException{
Class<? extends DBBean> c = this.getClass(); Class<? extends DBBean> c = this.getClass();
DBBeanConfig config = getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
if( this.getId() == null ) if( this.getId() == null )
throw new NoSuchElementException("ID field is null( Has the bean been saved?)!"); throw new NoSuchElementException("ID field is null( Has the bean been saved?)!");
@ -366,7 +301,7 @@ public abstract class DBBean {
*/ */
public static <T extends DBBean> List<T> load(DBConnection db, Class<T> c) throws SQLException { public static <T extends DBBean> List<T> load(DBConnection db, Class<T> c) throws SQLException {
// Initiate a BeanConfig if there is non // Initiate a BeanConfig if there is non
DBBeanConfig config = getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
// Generate query // Generate query
String sql = "SELECT * FROM "+config.tableName; String sql = "SELECT * FROM "+config.tableName;
logger.fine("Load All query("+c.getName()+"): "+sql); logger.fine("Load All query("+c.getName()+"): "+sql);
@ -386,7 +321,7 @@ public abstract class DBBean {
*/ */
public static <T extends DBBean> T load(DBConnection db, Class<T> c, long id) throws SQLException { public static <T extends DBBean> T load(DBConnection db, Class<T> c, long id) throws SQLException {
// Initiate a BeanConfig if there is non // Initiate a BeanConfig if there is non
DBBeanConfig config = getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
// Generate query // Generate query
String sql = "SELECT * FROM "+config.tableName+" WHERE "+config.idColumn+"=? LIMIT 1"; String sql = "SELECT * FROM "+config.tableName+" WHERE "+config.idColumn+"=? LIMIT 1";
logger.fine("Load query("+c.getName()+" id:"+id+"): "+sql); logger.fine("Load query("+c.getName()+" id:"+id+"): "+sql);
@ -402,7 +337,7 @@ public abstract class DBBean {
* WARNING: Experimental * WARNING: Experimental
*/ */
public static void create(DBConnection sql, Class<? extends DBBean> c) throws SQLException{ public static void create(DBConnection sql, Class<? extends DBBean> c) throws SQLException{
DBBeanConfig config = getBeanConfig( c ); DBBeanConfig config = DBBeanConfig.getBeanConfig( c );
// Generate the SQL // Generate the SQL
StringBuilder query = new StringBuilder(); StringBuilder query = new StringBuilder();
@ -415,7 +350,7 @@ public abstract class DBBean {
for( Field field : config.fields ){ for( Field field : config.fields ){
query.append(" "); query.append(" ");
query.append( field.getName() ); query.append( DBBeanConfig.getFieldName(field) );
query.append( classToDBName(c) ); query.append( classToDBName(c) );
query.append(", "); query.append(", ");
} }
@ -504,7 +439,7 @@ public abstract class DBBean {
} }
} }
/** /**
* @return the object id or null if the bean has not bean saved yet * @return the object id or null if the bean has not bean saved yet
*/ */
public Long getId(){ public Long getId(){
@ -517,7 +452,12 @@ public abstract class DBBean {
public static void cancelGBC(){ public static void cancelGBC(){
DBBeanSQLResultHandler.cancelGBC(); DBBeanSQLResultHandler.cancelGBC();
} }
////////////////// EXTENDABLE METHODS /////////////////////////
/** /**
* Will be called whenever the bean has been updated from the database. * Will be called whenever the bean has been updated from the database.
*/ */

View file

@ -0,0 +1,88 @@
package zutil.db.bean;
import zutil.log.LogUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.logging.Logger;
/**
* A Class that contains information about a bean
*/
class DBBeanConfig{
private static final Logger logger = LogUtil.getLogger();
/** This is a cache of all the initialized beans */
private static HashMap<String,DBBeanConfig> beanConfigs = new HashMap<String,DBBeanConfig>();
/** The name of the table in the DB **/
protected String tableName;
/** The name of the id column **/
protected String idColumn;
/** All the fields in the bean **/
protected ArrayList<Field> fields;
protected DBBeanConfig(){
fields = new ArrayList<Field>();
}
/**
* @return the configuration object for the specified class
*/
protected static DBBeanConfig getBeanConfig(Class<? extends DBBean> c){
if( !beanConfigs.containsKey( c.getName() ) )
initBeanConfig( c );
return beanConfigs.get( c.getName() );
}
/**
* Caches the fields
*/
private static void initBeanConfig(Class<? extends DBBean> c){
logger.fine("Initiating new DBBeanConfig( "+c.getName()+" )");
DBBeanConfig config = new DBBeanConfig();
// Find the table name
DBBean.DBTable tableAnn = c.getAnnotation(DBBean.DBTable.class);
if( tableAnn != null ){
config.tableName = tableAnn.value();
config.idColumn = tableAnn.idColumn();
}
else{
config.tableName = c.getSimpleName();
config.idColumn = "id";
}
// Add the fields in the bean and all the super classes fields
for(Class<?> cc = c; cc != DBBean.class ;cc = cc.getSuperclass()){
Field[] fields = cc.getDeclaredFields();
for( Field field : fields ){
int mod = field.getModifiers();
if( !Modifier.isTransient( mod ) &&
!Modifier.isAbstract( mod ) &&
!Modifier.isFinal( mod ) &&
!Modifier.isStatic( mod ) &&
!Modifier.isInterface( mod ) &&
!Modifier.isNative( mod ) &&
!config.fields.contains( field )){
config.fields.add( field );
}
}
if( tableAnn == null || !tableAnn.superBean() )
break;
}
beanConfigs.put(c.getName(), config);
}
protected static String getFieldName(Field field){
String name = null;
if(field.getDeclaredAnnotation(DBBean.DBColumn.class) != null)
name = field.getDeclaredAnnotation(DBBean.DBColumn.class).value();
else
name = field.getName();
return name;
}
}

View file

@ -26,7 +26,6 @@ package zutil.db.bean;
import zutil.db.DBConnection; import zutil.db.DBConnection;
import zutil.db.SQLResultHandler; import zutil.db.SQLResultHandler;
import zutil.db.bean.DBBean.DBBeanConfig;
import zutil.db.bean.DBBean.DBLinkTable; import zutil.db.bean.DBBean.DBLinkTable;
import zutil.log.LogUtil; import zutil.log.LogUtil;
@ -114,7 +113,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
this.bean_class = cl; this.bean_class = cl;
this.list = list; this.list = list;
this.db = db; this.db = db;
this.bean_config = DBBean.getBeanConfig( cl ); this.bean_config = DBBeanConfig.getBeanConfig( cl );
// Initiate DBBeanGarbageCollector // Initiate DBBeanGarbageCollector
if( timer == null ){ if( timer == null ){
@ -207,7 +206,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
* @return a new instance of the bean * @return a new instance of the bean
*/ */
protected DBBean createBean(ResultSet result) throws SQLException{ protected DBBean createBean(ResultSet result) throws SQLException{
try { try {
Long id = result.getLong( "id" ); Long id = result.getLong( "id" );
DBBean obj = getCachedDBBean(bean_class, id, result); DBBean obj = getCachedDBBean(bean_class, id, result);
if( obj != null ) if( obj != null )
@ -222,6 +221,8 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
// Update fields // Update fields
updateBean( result, obj ); updateBean( result, obj );
return obj; return obj;
} catch (SQLException e) {
throw e;
} catch (Exception e) { } catch (Exception e) {
throw new SQLException(e); throw new SQLException(e);
} }
@ -240,7 +241,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
obj.processing_update = true; obj.processing_update = true;
// Get the rest // Get the rest
for( Field field : bean_config.fields ){ for( Field field : bean_config.fields ){
String name = field.getName(); String name = DBBeanConfig.getFieldName(field);
// Another DBBean class // Another DBBean class
if( DBBean.class.isAssignableFrom( field.getType() )){ if( DBBean.class.isAssignableFrom( field.getType() )){
@ -257,7 +258,7 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
field.getAnnotation( DBLinkTable.class ) != null){ field.getAnnotation( DBLinkTable.class ) != null){
if(db != null){ if(db != null){
DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class ); DBLinkTable linkTable = field.getAnnotation( DBLinkTable.class );
DBBeanConfig subConfig = DBBean.getBeanConfig( linkTable.beanClass() ); DBBeanConfig subConfig = DBBeanConfig.getBeanConfig( linkTable.beanClass() );
String linkTableName = linkTable.table(); String linkTableName = linkTable.table();
String subTable = subConfig.tableName; String subTable = subConfig.tableName;
String idcol = (linkTable.idColumn().isEmpty() ? bean_config.tableName : linkTable.idColumn() ); String idcol = (linkTable.idColumn().isEmpty() ? bean_config.tableName : linkTable.idColumn() );
@ -277,8 +278,6 @@ public class DBBeanSQLResultHandler<T> implements SQLResultHandler<T>{
else else
obj.setFieldValue(field, result.getObject(name)); obj.setFieldValue(field, result.getObject(name));
} }
} catch (Exception e) {
throw new SQLException(e);
} finally{ } finally{
obj.processing_update = false; obj.processing_update = false;
} }