commit e56138919219ba62c6afd455da287ac7a14d1e82 Author: Miguel Ferreira Date: Thu May 11 12:15:13 2023 +0100 original diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0ef1cc6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +# NetBeans specific # +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml + +# Class Files # +*.class + +# Package Files # +*.jar +*.war +*.ear diff --git a/pom.xml b/pom.xml new file mode 100755 index 0000000..43e0aac --- /dev/null +++ b/pom.xml @@ -0,0 +1,13 @@ + + + 4.0.0 + net.sf + jeasyorm + 0.9.1 + jar + + UTF-8 + 1.8 + 1.8 + + \ No newline at end of file diff --git a/src/main/java/net/sf/jeasyorm/AbstractEntityManager.java b/src/main/java/net/sf/jeasyorm/AbstractEntityManager.java new file mode 100755 index 0000000..8bf5bdf --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/AbstractEntityManager.java @@ -0,0 +1,217 @@ +package net.sf.jeasyorm; + +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import net.sf.jeasyorm.Mapping.FieldInfo; + +public abstract class AbstractEntityManager extends EntityManager { + + private SqlTranslator sqlTranslator; + + protected AbstractEntityManager(Connection connection) { + super(connection); + } + + public void setSqlTranslator(SqlTranslator sqlTranslator) { + this.sqlTranslator = sqlTranslator; + } + + protected PreparedStatement prepareStatement(String sql, String[] columnNames) { + try { + String finalSql = sqlTranslator != null ? sqlTranslator.getTranslatedSql(sql) : sql; + if (columnNames == null || columnNames.length <= 0) { + return getConnection().prepareStatement(finalSql); + } else { + return getConnection().prepareStatement(finalSql, columnNames); + } + } catch (SQLException e) { + throw new RuntimeSQLException("Error preparing statement [" + sql + "]", e); + } + } + + protected void close(ResultSet rs) { + if (rs != null) { + try { + rs.close(); + } catch (Exception e) { + /* ignore */ } + } + } + + protected void close(PreparedStatement stmt) { + if (stmt != null) { + try { + stmt.close(); + } catch (Exception e) { + /* ignore */ } + } + } + + protected Object getObject(ResultSet rs, Mapping mapping) { + Object o; + try { + o = mapping.getConstructor() != null ? mapping.getConstructor().newInstance(this) : + mapping.getEntityClass().newInstance(); + } catch (Exception e) { + throw new RuntimeSQLException("Can't create object of type '" + mapping.getEntityClass().getName() + "'", e); + } + try { + ResultSetMetaData metadata = rs.getMetaData(); + for (int index=1; index<=metadata.getColumnCount(); index++) { + int sqlType = metadata.getColumnType(index); + String columnName = metadata.getColumnName(index); + FieldInfo fi = mapping.getFieldForColumn(columnName); + if (fi == null) { + columnName = metadata.getColumnLabel(index); + fi = mapping.getFieldForColumn(columnName); + } + if (fi == null) { + if (columnName.contains("__")) continue; // ignore + throw new RuntimeSQLException("Can't find field for column '" + columnName + "'"); + } + try { + Object v = getValue(rs, index, fi.getType(), sqlType); + set(o, fi, v); + } catch (RuntimeSQLException e) { + throw new RuntimeSQLException("Can't read column '" + columnName + "'", e); + } + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } + return o; + } + + protected Object get(Object o, FieldInfo fi) { + try { + if (fi.getGetter() != null) { + return fi.getGetter().invoke(o); + } else if (fi.getField() != null) { + return fi.getField().get(o); + } else { + throw new RuntimeSQLException("Neither field nor getter found for field '" + fi.getName() + "'"); + } + } catch (IllegalArgumentException e) { + throw new RuntimeSQLException("Error getting field '" + fi.getName() + "'"); + } catch (IllegalAccessException e) { + throw new RuntimeSQLException("Error getting field '" + fi.getName() + "'"); + } catch (InvocationTargetException e) { + throw new RuntimeSQLException("Error getting field '" + fi.getName() + "'"); + } + } + + protected void set(Object o, FieldInfo fi, Object v) { + try { + if (fi.getSetter() != null) { + fi.getSetter().invoke(o, v); + } else if (fi.getField() != null) { + fi.getField().set(o, v); + } else { + throw new RuntimeSQLException("Neither field nor setter found for field '" + fi.getName() + "'"); + } + } catch (IllegalArgumentException e) { + throw new RuntimeSQLException("Error setting field '" + fi.getName() + "'"); + } catch (IllegalAccessException e) { + throw new RuntimeSQLException("Error setting field '" + fi.getName() + "'"); + } catch (InvocationTargetException e) { + throw new RuntimeSQLException("Error setting field '" + fi.getName() + "'"); + } + } + + protected void setParameter(PreparedStatement stmt, int index, Object value, int sqlType) { + try { + if (value == null) { + stmt.setNull(index, sqlType); + } else if (value instanceof Boolean) { + stmt.setBoolean(index, (Boolean) value); + } else if (value instanceof Byte) { + stmt.setByte(index, (Byte) value); + } else if (value instanceof Short) { + stmt.setShort(index, (Short) value); + } else if (value instanceof Integer) { + stmt.setInt(index, (Integer) value); + } else if (value instanceof Long) { + stmt.setLong(index, (Long) value); + } else if (value instanceof Float) { + stmt.setFloat(index, (Float) value); + } else if (value instanceof Double) { + stmt.setDouble(index, (Double) value); + } else if (value instanceof byte[]) { + stmt.setBytes(index, (byte[]) value); + } else if (value instanceof char[]) { + stmt.setString(index, new String((char[]) value)); + } else if (value instanceof String) { + stmt.setString(index, (String) value); + } else if (value instanceof BigDecimal) { + stmt.setBigDecimal(index, (BigDecimal) value); + } else if (value instanceof java.util.Date) { + stmt.setTimestamp(index, new java.sql.Timestamp(((java.util.Date) value).getTime())); + } else if (value instanceof java.sql.Date) { + stmt.setDate(index, (java.sql.Date) value); + } else if (value instanceof java.sql.Time) { + stmt.setTime(index, (java.sql.Time) value); + } else if (value instanceof java.sql.Timestamp) { + stmt.setTimestamp(index, (java.sql.Timestamp) value); + } else if (value instanceof java.sql.Clob) { + stmt.setClob(index, (java.sql.Clob) value); + } else if (value instanceof java.sql.Blob) { + stmt.setBlob(index, (java.sql.Blob) value); + } else { + throw new RuntimeSQLException("Unsupported type '" + value.getClass().getName() + "'"); + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } + } + + protected Object getValue(ResultSet rs, int index, Class type, int sqlType) { + try { + if (type == Boolean.class) { + return rs.getBoolean(index); + } else if (type == Byte.class) { + return rs.getByte(index); + } else if (type == Short.class) { + return rs.getShort(index); + } else if (type == Integer.class) { + return rs.getInt(index); + } else if (type == Long.class) { + return rs.getLong(index); + } else if (type == Float.class) { + return rs.getFloat(index); + } else if (type == Double.class) { + return rs.getDouble(index); + } else if (type == byte[].class) { + return rs.getBytes(index); + } else if (type == char[].class) { + return rs.getString(index).toCharArray(); + } else if (type == String.class) { + return rs.getString(index); + } else if (type == BigDecimal.class) { + return rs.getBigDecimal(index); + } else if (type == java.util.Date.class) { + return new java.util.Date(rs.getTimestamp(index).getTime()); + } else if (type == java.sql.Date.class) { + return rs.getDate(index); + } else if (type == java.sql.Time.class) { + return rs.getTime(index); + } else if (type == java.sql.Timestamp.class) { + return rs.getTimestamp(index); + } else if (type == java.sql.Clob.class) { + return rs.getClob(index); + } else if (type == java.sql.Blob.class) { + return rs.getBlob(index); + } else { + throw new RuntimeSQLException("Unsupported type '" + type.getName() + "'"); + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } + } + +} diff --git a/src/main/java/net/sf/jeasyorm/BasicEntityManager.java b/src/main/java/net/sf/jeasyorm/BasicEntityManager.java new file mode 100755 index 0000000..f0f0656 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/BasicEntityManager.java @@ -0,0 +1,456 @@ +package net.sf.jeasyorm; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import net.sf.jeasyorm.Mapping.ColumnInfo; +import net.sf.jeasyorm.Mapping.FieldInfo; + +public class BasicEntityManager extends AbstractEntityManager { + + public BasicEntityManager(Connection connection) { + super(connection); + } + + /** + * + * @param entityClass + * @return + */ + @Override + protected SqlInfo newSqlInfo(Class entityClass) { + Mapping mapping = Mapping.getMapping(this, entityClass); + SqlInfo info = new SqlInfo(mapping); + StringBuffer selectColumns = new StringBuffer(); + StringBuffer insertColumns = new StringBuffer(); + StringBuffer insertPlaceholders = new StringBuffer(); + StringBuffer updateSet = new StringBuffer(); + StringBuffer where = new StringBuffer(); + for (ColumnInfo ci : mapping.getColumns()) { + if (selectColumns.length() > 0) { + selectColumns.append(", "); + } + selectColumns.append(ci.getName()); + if (!ci.isAutoIncrement()) { + if (insertColumns.length() > 0) { + insertColumns.append(", "); + } + insertColumns.append(ci.getName()); + if (insertPlaceholders.length() > 0) { + insertPlaceholders.append(", "); + } + insertPlaceholders.append("?"); + } + if (ci.isPrimaryKey()) { + if (where.length() > 0) { + where.append(" and "); + } + where.append(ci.getName()); + where.append(" = ?"); + } else { + if (updateSet.length() > 0) { + updateSet.append(", "); + } + updateSet.append(ci.getName()); + updateSet.append(" = ?"); + } + } + String tableName = (mapping.getSchemaName() != null ? mapping.getSchemaName() + "." : "") + + mapping.getTableName(); + info.loadSql = "select " + selectColumns + " from " + tableName + " where " + where; + info.selectSql = "select " + selectColumns + " from " + tableName; + info.insertSql = "insert into " + tableName + " (" + insertColumns + ") values (" + insertPlaceholders + ")"; + info.updateSql = "update " + tableName + " set " + updateSet + " where " + where; + info.deleteSql = "delete from " + tableName + " where " + where; + return info; + } + + @SuppressWarnings("unchecked") + @Override + public T load(Class entityClass, Object... pk) { + SqlInfo info = getSqlInfo(this, entityClass); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(info.loadSql, null); + int i = 0; + for (ColumnInfo ci : info.mapping.getColumns()) { + if (ci.isPrimaryKey()) { + setParameter(stmt, i + 1, pk[i], ci.getType()); + i++; + } + } + ResultSet rs = null; + try { + rs = stmt.executeQuery(); + T entity = null; + if (rs.next()) { + entity = (T) getObject(rs, info.mapping); + } + if (rs.next()) { + throw new RuntimeSQLException("Multiple rows returned for statement [" + info.loadSql + "]"); + } + return entity; + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + info.loadSql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + + protected String getSql(SqlInfo info, String query) { + String lcQuery = query.trim().toLowerCase(); + if (lcQuery.startsWith("from")) { + int pos = info.selectSql.indexOf(" from "); + return info.selectSql.substring(0, pos + 1) + query; + } else if (lcQuery.startsWith("where") || lcQuery.startsWith("order")) { + return info.selectSql + " " + query; + } else { + return query; + } + } + + @SuppressWarnings("unchecked") + public T findUnique(Class entityClass, String query, Object... params) { + boolean isNative = Utils.isNativeType(entityClass); + SqlInfo info = isNative ? null : getSqlInfo(this, entityClass); + String sql = isNative ? query : getSql(info, query); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(sql, null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + ResultSet rs = null; + try { + rs = stmt.executeQuery(); + T entity = null; + if (rs.next()) { + entity = !isNative ? (T) getObject(rs, info.mapping) : (T) getValue(rs, 1, entityClass, Types.VARCHAR); + } + if (rs.next()) { + throw new RuntimeSQLException("Multiple rows returned for statement [" + sql + "]"); + } + return entity; + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + + @SuppressWarnings("unchecked") + public List find(Class entityClass, String query, Object... params) { + boolean isNative = Utils.isNativeType(entityClass); + SqlInfo info = isNative ? null : getSqlInfo(this, entityClass); + String sql = isNative ? query : getSql(info, query); + List entities = new ArrayList(); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(sql, null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + ResultSet rs = null; + try { + rs = stmt.executeQuery(); + while (rs.next()) { + T entity = !isNative ? (T) getObject(rs, info.mapping) : (T) getValue(rs, 1, entityClass, Types.VARCHAR); + entities.add(entity); + } + return entities; + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + + public int count(String sql, Object... params) { + PreparedStatement stmt = null; + try { + int pos1 = sql.indexOf(" from "); + int pos2 = sql.lastIndexOf(" order by "); + stmt = prepareStatement("select count(*)" + sql.substring(pos1, pos2 > pos1 ? pos2 : sql.length()), null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + ResultSet rs = null; + try { + rs = stmt.executeQuery(); + if (rs.next()) { + return rs.getInt(1); + } + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + return 0; + } + + @SuppressWarnings("unchecked") + public Page find(Class entityClass, int pageNum, int pageSize, String query, Object... params) { + boolean isNative = Utils.isNativeType(entityClass); + SqlInfo info = isNative ? null : getSqlInfo(this, entityClass); + String sql = isNative ? query : getSql(info, query); + List entities = new ArrayList(); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(sql + " limit " + pageSize + " offset " + (pageNum * pageSize), null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + ResultSet rs = null; + try { + rs = stmt.executeQuery(); + while (rs.next()) { + T entity = !isNative ? (T) getObject(rs, info.mapping) : (T) getValue(rs, 1, entityClass, Types.VARCHAR); + entities.add(entity); + } + int totalSize = (pageNum * pageSize) + entities.size(); + if (entities.size() >= pageSize) { + totalSize = Math.max(totalSize, count(sql, params)); + } + return new Page(entities, pageNum, pageSize, totalSize); + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + + public Iterator iterator(Class entityClass, String query, Object... params) { + SqlInfo info = getSqlInfo(this, entityClass); + String sql = getSql(info, query); + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = prepareStatement(sql, null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + rs = stmt.executeQuery(); + return new ResultSetIterator(stmt, rs, entityClass); + } catch (RuntimeSQLException se) { + close(rs); + close(stmt); + throw se; + } catch (Exception e) { + close(rs); + close(stmt); + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } + } + + public int execute(String sql, Object... params) { + PreparedStatement stmt = null; + try { + stmt = prepareStatement(sql, null); + for (int i = 0; i < params.length; i++) { + setParameter(stmt, i + 1, params[i], Types.VARCHAR); + } + return stmt.executeUpdate(); + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(stmt); + } + } + + public T insert(T entity) { + SqlInfo info = getSqlInfo(this, entity.getClass()); + PreparedStatement stmt = null; + try { + List columnNames = new ArrayList(); + for (ColumnInfo ci : info.mapping.getColumns()) { + if (ci.isAutoIncrement()) { + columnNames.add(ci.getName()); + } + } + stmt = prepareStatement(info.insertSql, columnNames.toArray(new String[columnNames.size()])); + int i = 0; + for (ColumnInfo ci : info.mapping.getColumns()) { + if (!ci.isAutoIncrement()) { + FieldInfo fi = info.mapping.getFieldForColumn(ci); + Object value = get(entity, fi); + if (ci.isPrimaryKey() && value == null) { + value = getPrimaryKey(info.mapping, ci); + set(entity, fi, Utils.convertTo(value, fi.getType())); + } + setParameter(stmt, i + 1, value, ci.getType()); + i++; + } + } + int num = stmt.executeUpdate(); + if (num < 1) { + throw new RuntimeSQLException("Error inserting entity"); + } + if (columnNames.size() > 0) { + ResultSet rs = null; + try { + rs = stmt.getGeneratedKeys(); + for (String columnName : columnNames) { + FieldInfo fi = info.mapping.getFieldForColumn(columnName); + ColumnInfo ci = info.mapping.getColumnForColumn(columnName); + rs.next(); + set(entity, fi, getValue(rs, 1, fi.getType(), ci.getType())); + } + } catch (SQLException e) { + throw new RuntimeSQLException("Error updating generated keys", e); + } finally { + close(rs); + } + } + } catch (SQLException e) { + throw new RuntimeSQLException("Error inserting entity", e); + } finally { + close(stmt); + } + return null; + } + + protected Object getPrimaryKey(Mapping mapping, ColumnInfo ci) { + return null; + } + + public void update(T entity) { + SqlInfo info = getSqlInfo(this, entity.getClass()); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(info.updateSql, null); + int i = 0; + for (ColumnInfo ci : info.mapping.getColumns()) { + if (!ci.isPrimaryKey()) { + FieldInfo fi = info.mapping.getFieldForColumn(ci); + Object value = get(entity, fi); + setParameter(stmt, i + 1, value, ci.getType()); + i++; + } + } + for (ColumnInfo ci : info.mapping.getColumns()) { + if (ci.isPrimaryKey()) { + FieldInfo fi = info.mapping.getFieldForColumn(ci); + Object value = get(entity, fi); + setParameter(stmt, i + 1, value, ci.getType()); + i++; + } + } + int num = stmt.executeUpdate(); + if (num < 1) { + throw new RuntimeSQLException("Error updating entity"); + } + } catch (SQLException e) { + throw new RuntimeSQLException("Error updating entity", e); + } finally { + close(stmt); + } + } + + public void delete(T entity) { + SqlInfo info = getSqlInfo(this, entity.getClass()); + PreparedStatement stmt = null; + try { + stmt = prepareStatement(info.deleteSql, null); + int i = 0; + for (ColumnInfo ci : info.mapping.getColumns()) { + FieldInfo fi = info.mapping.getFieldForColumn(ci); + if (ci.isPrimaryKey()) { + Object value = get(entity, fi); + setParameter(stmt, i + 1, value, ci.getType()); + i++; + } + } + int num = stmt.executeUpdate(); + if (num < 1) { + throw new RuntimeSQLException("Error deleting entity"); + } + } catch (SQLException e) { + throw new RuntimeSQLException("Error deleting entity", e); + } finally { + close(stmt); + } + } + + public class ResultSetIterator implements Iterator { + + private PreparedStatement stmt; + private ResultSet rs; + boolean isNative; + private Class entityClass; + private Mapping mapping; + boolean hasNext; + + protected ResultSetIterator(PreparedStatement stmt, ResultSet rs, Class entityClass) { + this.stmt = stmt; + this.rs = rs; + this.isNative = Utils.isNativeType(entityClass); + this.entityClass = entityClass; + this.mapping = isNative ? null : Mapping.getMapping(BasicEntityManager.this, entityClass); + try { + this.hasNext = rs.next(); + } catch (SQLException e) { + this.hasNext = false; + } + } + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + @SuppressWarnings("unchecked") + public T next() { + T entity = !isNative ? (T) getObject(rs, mapping) : (T) getValue(rs, 1, entityClass, Types.VARCHAR); + try { + this.hasNext = rs.next(); + } catch (SQLException e) { + this.hasNext = false; + } + return entity; + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + + public void close() { + BasicEntityManager.this.close(rs); + BasicEntityManager.this.close(stmt); + } + + } + +} diff --git a/src/main/java/net/sf/jeasyorm/Configuration.java b/src/main/java/net/sf/jeasyorm/Configuration.java new file mode 100755 index 0000000..f966b4b --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/Configuration.java @@ -0,0 +1,5 @@ +package net.sf.jeasyorm; + +public class Configuration { + +} diff --git a/src/main/java/net/sf/jeasyorm/DerbyEntityManager.java b/src/main/java/net/sf/jeasyorm/DerbyEntityManager.java new file mode 100755 index 0000000..83185e4 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/DerbyEntityManager.java @@ -0,0 +1,65 @@ +package net.sf.jeasyorm; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; + +public class DerbyEntityManager extends BasicEntityManager { + + private boolean pagingSupported = false; + + public DerbyEntityManager(Connection connection) throws SQLException { + super(connection); + DatabaseMetaData metadata = connection.getMetaData(); + String prodName = metadata.getDatabaseProductName(); + if (prodName.indexOf("Derby") < 0) throw new RuntimeException("Database not supported"); + int majorVersion = metadata.getDatabaseMajorVersion(); + int minorVersion = metadata.getDatabaseMinorVersion(); + if (majorVersion > 10 || (majorVersion == 10 && minorVersion >= 5)) pagingSupported = true; + } + + @SuppressWarnings("unchecked") + public Page find(Class entityClass, int pageNum, int pageSize, String query, Object... params) { + if (!pagingSupported) throw new UnsupportedOperationException(); + boolean isNative = Utils.isNativeType(entityClass); + SqlInfo info = isNative ? null : getSqlInfo(this, entityClass); + String sql = isNative ? query : getSql(info, query); + List entities = new ArrayList(); + PreparedStatement stmt = null; + try { + String pagingSql = sql + " offset " + (pageNum*pageSize) + " rows fetch next " + pageSize + " rows only"; + stmt = prepareStatement(pagingSql, null); + for (int i=0; i= pageSize) { + totalSize = Math.max(totalSize, count(sql, params)); + } + return new Page(entities, pageNum, pageSize, totalSize); + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + + +} diff --git a/src/main/java/net/sf/jeasyorm/EntityManager.java b/src/main/java/net/sf/jeasyorm/EntityManager.java new file mode 100755 index 0000000..962a34a --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/EntityManager.java @@ -0,0 +1,144 @@ +package net.sf.jeasyorm; + +import java.lang.reflect.Constructor; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; + +public abstract class EntityManager { + + private static final Logger log = Logger.getLogger(EntityManager.class.getName()); + + private static Map infosByClassName = new HashMap(); + + private static List> entityManagerClasses = + new ArrayList>(); + static { + register(BasicEntityManager.class); + register(HSQLDBEntityManager.class); + register(OracleEntityManager.class); + register(PostgreSQLEntityManager.class); + register(DerbyEntityManager.class); + // MySQL (5.1) supported by BasicEntityManager + // H2 supported by BasicEntityManager + } + + private String cache; + private Connection connection; + private NameGuesser nameGuesser; + + public static EntityManager getInstance(Connection connection) { + return getInstance(null, connection); + } + + public static EntityManager getInstance(String cache, Connection connection) { + for (Class emClass : entityManagerClasses) { + try { + Constructor c = emClass.getConstructor(Connection.class); + EntityManager em = c.newInstance(connection); + em.setCache(cache); + return em; + } catch (Exception e) { + // ignore + } + } + return null; + } + + public static void clear() { + infosByClassName.clear(); + } + + @SuppressWarnings("unchecked") + public static void register(String entityManagerClassName) { + try { + entityManagerClasses.add(0, (Class) Class.forName(entityManagerClassName)); + } catch (Exception e) { + throw new RuntimeException("Class '" + entityManagerClassName + "' not found!"); + } + } + + public static void register(Class entityManagerClass) { + entityManagerClasses.add(0, entityManagerClass); + } + + protected static SqlInfo getSqlInfo(EntityManager manager, Class entityClass) { + String key = (manager.getCache() != null ? manager.getCache() + ":" : "") + entityClass.getName(); + SqlInfo info = infosByClassName.get(key); + if (info == null && !infosByClassName.containsKey(key)) { + info = manager.newSqlInfo(entityClass); + infosByClassName.put(key, info); + } + return info; + } + + /** + * Constructors of child classes should throw an exception if they do not + * support the database type of the connection. + * (e.g. by checking connection.getMetaData().getDatabaseProductName()) + */ + protected EntityManager(Connection connection) { + this.connection = connection; + } + + public Connection getConnection() { return connection; } + public String getCache() { return cache; } + public void setCache(String cache) { this.cache = cache; } + public NameGuesser getNameGuesser() { + if (nameGuesser == null) nameGuesser = new SimpleNameGuesser(); + return nameGuesser; + } + public void setNameGuesser(NameGuesser nameGuesser) { this.nameGuesser = nameGuesser; } + + protected abstract SqlInfo newSqlInfo(Class entityClass); + + protected Mapping newMapping(Class entityClass) throws SQLException { + return new Mapping(this, entityClass); + } + + public abstract T load(Class entityClass, Object... pk); + + public abstract T findUnique(Class entityClass, String query, Object... params); + + public abstract List find(Class entityClass, String query, Object... params); + + public abstract Page find(Class entityClass, int pageNum, int pageSize, String query, Object... params); + + public abstract Iterator iterator(Class entityClass, String query, Object... params); + + public abstract int count(String query, Object... params); + + public abstract T insert(T entity); + + public abstract void update(T entity); + + public abstract void delete(T entity); + + protected void log(Level level, String message, Object... params) { + log.log(level, message, params); + } + + protected void log(Level level, String message, Throwable t) { + log.log(level, message, t); + } + + protected static class SqlInfo { + + protected Mapping mapping; + protected String loadSql; + protected String selectSql; + protected String insertSql; + protected String updateSql; + protected String deleteSql; + + protected SqlInfo(Mapping mapping) { + this.mapping = mapping; + } + } +} diff --git a/src/main/java/net/sf/jeasyorm/HSQLDBEntityManager.java b/src/main/java/net/sf/jeasyorm/HSQLDBEntityManager.java new file mode 100755 index 0000000..2c48ede --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/HSQLDBEntityManager.java @@ -0,0 +1,37 @@ +package net.sf.jeasyorm; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import net.sf.jeasyorm.Mapping.ColumnInfo; + +public class HSQLDBEntityManager extends BasicEntityManager { + + public HSQLDBEntityManager(Connection connection) throws SQLException { + super(connection); + String prodName = connection.getMetaData().getDatabaseProductName(); + if (prodName.indexOf("HSQL") < 0) throw new RuntimeException("Database not supported"); + } + + protected Object getPrimaryKey(Mapping mapping, ColumnInfo ci) { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = prepareStatement("call next value for JEASYORM_SEQUENCE", null); + rs = stmt.executeQuery(); + if (rs.next()) { + return rs.getLong(1); + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } finally { + close(rs); + close(stmt); + } + return null; + } + + +} diff --git a/src/main/java/net/sf/jeasyorm/Mapping.java b/src/main/java/net/sf/jeasyorm/Mapping.java new file mode 100755 index 0000000..e023954 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/Mapping.java @@ -0,0 +1,271 @@ +package net.sf.jeasyorm; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import net.sf.jeasyorm.annotation.Column; +import net.sf.jeasyorm.annotation.Table; +import net.sf.jeasyorm.annotation.Transient; + +public class Mapping { + + private static Map mappingsByClassName = new HashMap(); + + protected Class entityClass; + protected Constructor constructor; + protected Map fieldsByName = new HashMap(); + protected Map fieldsByLcColumnName = new HashMap(); + + protected String catalogName; + protected String schemaName; + protected String tableName; + protected List columns = new ArrayList(); + protected Map columnsByLcColumnName = new HashMap(); + + public static Mapping getMapping(EntityManager manager, Class entityClass) { + String key = (manager.getCache() != null ? manager.getCache() + ":" : "") + entityClass.getName(); + Mapping mapping = mappingsByClassName.get(key); + if (mapping == null && !mappingsByClassName.containsKey(key)) { + try { + mapping = manager.newMapping(entityClass); + mappingsByClassName.put(key, mapping); + } catch (SQLException e) { + mappingsByClassName.put(key, null); + } + } + return mapping; + } + + public Mapping(EntityManager manager, Class entityClass) throws SQLException { + this.entityClass = entityClass; + NameGuesser nameGuesser = manager.getNameGuesser(); + // transient fields + Set transientFieldNames = new HashSet(); + // column names as specified with @Column annotation + Map columnNamesByFieldName = new HashMap(); + // get fields + for (Field field : entityClass.getDeclaredFields()) { + Transient t = field.getAnnotation(Transient.class); + if (t != null) { + transientFieldNames.add(field.getName()); + } else if (isAccessible(field)) { + this.fieldsByName.put(field.getName(), new FieldInfo(field.getName(), field.getType(), field, null, null)); + } + Column c = field.getAnnotation(Column.class); + if (c != null && !"".equals(c.name())) columnNamesByFieldName.put(field.getName(), c.name()); + } + // get methods (getters and setters) + for (Method m : entityClass.getDeclaredMethods()) { + String name = m.getName(); + boolean getter = false; + if (name.length() > 3 && ((getter = name.startsWith("get")) || name.startsWith("set")) && + Character.isUpperCase(name.charAt(3))) { + name = name.substring(3,4).toLowerCase() + name.substring(4); + Transient t = m.getAnnotation(Transient.class); + if (t != null) { + transientFieldNames.add(name); + this.fieldsByName.remove(name); + } else if (!transientFieldNames.contains(name) && isAccessible(m)) { + if (!this.fieldsByName.containsKey(name)) { + this.fieldsByName.put(name, new FieldInfo(name, m.getReturnType(), null, + getter ? m : null, getter ? null : m)); + } else if (getter) { + this.fieldsByName.get(name).getter = m; + } else { + this.fieldsByName.get(name).setter = m; + } + } + Column c = m.getAnnotation(Column.class); + if (c != null && !"".equals(c.name())) columnNamesByFieldName.put(name, c.name()); + } + } + try { + constructor = entityClass.getConstructor(EntityManager.class); + } catch (Exception e) { + // ignore + } + for (FieldInfo fi : this.fieldsByName.values()) { + if (columnNamesByFieldName.get(fi.name) != null) { + this.fieldsByLcColumnName.put(columnNamesByFieldName.get(fi.name).toLowerCase(), fi); + } else { + for (String columnName : nameGuesser.guessColumnName(entityClass, fi.name)) { + this.fieldsByLcColumnName.put(columnName.toLowerCase(), fi); + } + } + } + Transient t = entityClass.getAnnotation(Transient.class); + if (t == null) { + String schemaName = "%"; + String[] tableNames; + Table ta = entityClass.getAnnotation(Table.class); + if (ta != null && !"".equals(ta.schema())) { + schemaName = ta.schema(); + } + if (ta != null && !"".equals(ta.name())) { + tableNames = new String[] { ta.name() }; + } else { + tableNames = nameGuesser.guessTableName(entityClass); + } + DatabaseMetaData metadata = manager.getConnection().getMetaData(); + String[] name = getTableName(metadata, schemaName, tableNames); + this.catalogName = name[0]; + this.schemaName = name[1]; + this.tableName = name[2]; + if (this.tableName == null) { + throw new RuntimeException("Class '" + entityClass.getName() + "': Table '" + + Utils.join(tableNames, "'/'") + "' does not exist!"); + } + ResultSet rs = metadata.getColumns(this.catalogName, this.schemaName, this.tableName, null); + int numColumns = rs.getMetaData().getColumnCount(); + while (rs.next()) { + String columnName = rs.getString(4); + int columnType = rs.getInt(5); + String nullable = rs.getString(18); + String autoIncrement = numColumns >= 23 ? rs.getString(23) : null; + ColumnInfo column = new ColumnInfo(columnName, columnType, false, + nullable == null || "YES".equals(nullable), "YES".equals(autoIncrement)); + this.columns.add(column); + this.columnsByLcColumnName.put(columnName.toLowerCase(), column); + if (fieldsByLcColumnName.get(columnName.toLowerCase()) == null) { + throw new RuntimeException("Class '" + entityClass.getName() + + "': No field for column '" + this.tableName + "." + columnName + "'!"); + } + } + rs.close(); + rs = metadata.getPrimaryKeys(this.catalogName, this.schemaName, this.tableName); + while (rs.next()) { + String columnName = rs.getString(4); + for (ColumnInfo ci : this.columns) { + if (columnName.equals(ci.name)) ci.primaryKey = true; + } + } + rs.close(); + } + } + + protected String[] getTableName(DatabaseMetaData metadata, String schemaName, String tableNames[]) throws SQLException { + String[] name = null; + for (String tableName : tableNames) { + ResultSet rs = metadata.getTables(null, schemaName, tableName.toLowerCase(), null); + if (rs.next()) name = new String[] { rs.getString(1), rs.getString(2), rs.getString(3) }; + rs.close(); + if (name != null) break; + rs = metadata.getTables(null, schemaName, tableName.toUpperCase(), null); + if (rs.next()) name = new String[] { rs.getString(1), rs.getString(2), rs.getString(3) }; + rs.close(); + if (name != null) break; + rs = metadata.getTables(null, schemaName, "%", null); + while (rs.next()) { + String dbTableName = rs.getString(3); + if (tableName.equalsIgnoreCase(dbTableName)) { + name = new String[] { rs.getString(1), rs.getString(2), dbTableName }; + break; + } + } + rs.close(); + } + return name; + } + + protected boolean isAccessible(Field field) { + if ((field.getModifiers() & Modifier.PUBLIC) > 0) return true; + try { + field.setAccessible(true); + return true; + } catch (SecurityException e) { + return false; + } + } + + protected boolean isAccessible(Method m) { + if ((m.getModifiers() & Modifier.PUBLIC) > 0) return true; + try { + m.setAccessible(true); + return true; + } catch (SecurityException e) { + return false; + } + } + + public Class getEntityClass() { return entityClass; } + public Constructor getConstructor() { return constructor; } + + public String getCatalogName() { return catalogName; } + public String getSchemaName() { return schemaName; } + public String getTableName() { return tableName; } + + public Collection getFields() { return fieldsByName.values(); } + public FieldInfo getFieldForColumn(String columnName) { + return fieldsByLcColumnName.get(columnName.toLowerCase()); + } + public FieldInfo getFieldForColumn(ColumnInfo column) { + return fieldsByLcColumnName.get(column.name.toLowerCase()); + } + public List getColumns() { return columns; } + public ColumnInfo getColumnForColumn(String columnName) { + return columnsByLcColumnName.get(columnName.toLowerCase()); + } + + + public static class FieldInfo { + + protected String name; + protected Class type; + + protected Field field; + protected Method getter; + protected Method setter; + + protected FieldInfo(String name, Class type, Field field, Method getter, Method setter) { + this.name = name; + this.type = type; + this.field = field; + this.getter = getter; + this.setter = setter; + } + + public String getName() { return name; } + public Class getType() { return type; } + public Field getField() { return field; } + public Method getGetter() { return getter; } + public Method getSetter() { return setter; } + + } + + + public static class ColumnInfo { + + protected String name; + protected int type; + protected boolean primaryKey; + protected boolean nullable; + protected boolean autoIncrement; + + protected ColumnInfo(String name, int type, boolean primaryKey, boolean nullable, boolean autoIncrement) { + this.name = name; + this.type = type; + this.nullable = nullable; + this.autoIncrement = autoIncrement; + } + + public String getName() { return name; } + public int getType() { return type; } + public boolean isPrimaryKey() { return primaryKey; } + public boolean isAutoIncrement() { return autoIncrement; } + public boolean isNullable() { return nullable; } + + } + +} diff --git a/src/main/java/net/sf/jeasyorm/NameGuesser.java b/src/main/java/net/sf/jeasyorm/NameGuesser.java new file mode 100755 index 0000000..de5f55a --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/NameGuesser.java @@ -0,0 +1,9 @@ +package net.sf.jeasyorm; + +public interface NameGuesser { + + public String[] guessTableName(Class entityClass); + + public String[] guessColumnName(Class entityClass, String field); + +} diff --git a/src/main/java/net/sf/jeasyorm/OracleEntityManager.java b/src/main/java/net/sf/jeasyorm/OracleEntityManager.java new file mode 100755 index 0000000..77243dc --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/OracleEntityManager.java @@ -0,0 +1,77 @@ +package net.sf.jeasyorm; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; + +import net.sf.jeasyorm.Mapping.ColumnInfo; + +public class OracleEntityManager extends BasicEntityManager { + + public OracleEntityManager(Connection connection) throws SQLException { + super(connection); + String prodName = connection.getMetaData().getDatabaseProductName(); + if (prodName.indexOf("Oracle") < 0) throw new RuntimeException("Database not supported"); + } + + protected Object getPrimaryKey(Mapping mapping, ColumnInfo ci) { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = prepareStatement("select jeasyorm_sequence.nextval from dual", null); + rs = stmt.executeQuery(); + if (rs.next()) { + return rs.getLong(1); + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } finally { + close(rs); + close(stmt); + } + return null; + } + + @SuppressWarnings("unchecked") + public Page find(Class entityClass, int pageNum, int pageSize, String query, Object... params) { + boolean isNative = Utils.isNativeType(entityClass); + SqlInfo info = isNative ? null : getSqlInfo(this, entityClass); + String sql = isNative ? query : getSql(info, query); + List entities = new ArrayList(); + PreparedStatement stmt = null; + try { + String pagingSql = "select * from (select t__.*, rownum as rownum__ from (" + sql + + ") t__ where rownum <= " + (pageNum*pageSize+pageSize) + ") where rownum__ > " + (pageNum*pageSize); + stmt = prepareStatement(pagingSql, null); + for (int i=0; i= pageSize) { + totalSize = Math.max(totalSize, count(sql, params)); + } + return new Page(entities, pageNum, pageSize, totalSize); + } catch (RuntimeSQLException se) { + throw se; + } catch (Exception e) { + throw new RuntimeSQLException("Error executing statement [" + sql + "]", e); + } finally { + close(rs); + } + } finally { + close(stmt); + } + } + +} diff --git a/src/main/java/net/sf/jeasyorm/Page.java b/src/main/java/net/sf/jeasyorm/Page.java new file mode 100755 index 0000000..55323fd --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/Page.java @@ -0,0 +1,25 @@ +package net.sf.jeasyorm; + +import java.util.ArrayList; +import java.util.Collection; + +public class Page extends ArrayList { + + private static final long serialVersionUID = 1L; + + private int pageNum; + private int pageSize; + private int totalSize; + + public Page(Collection elements, int pageNum, int pageSize, int totalSize) { + super(elements); + this.pageNum = pageNum; + this.pageSize = pageSize; + this.totalSize = totalSize; + } + + public int pageNumber() { return pageNum; } + public int pageSize() { return pageSize; } + public int totalSize() { return totalSize; } + +} diff --git a/src/main/java/net/sf/jeasyorm/PostgreSQLEntityManager.java b/src/main/java/net/sf/jeasyorm/PostgreSQLEntityManager.java new file mode 100755 index 0000000..6e57e1a --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/PostgreSQLEntityManager.java @@ -0,0 +1,36 @@ +package net.sf.jeasyorm; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import net.sf.jeasyorm.Mapping.ColumnInfo; + +public class PostgreSQLEntityManager extends BasicEntityManager { + + public PostgreSQLEntityManager(Connection connection) throws SQLException { + super(connection); + String prodName = connection.getMetaData().getDatabaseProductName(); + if (prodName.indexOf("PostgreSQL") < 0) throw new RuntimeException("Database not supported"); + } + + protected Object getPrimaryKey(Mapping mapping, ColumnInfo ci) { + PreparedStatement stmt = null; + ResultSet rs = null; + try { + stmt = prepareStatement("select nextval('jeasyorm_sequence')", null); + rs = stmt.executeQuery(); + if (rs.next()) { + return rs.getLong(1); + } + } catch (SQLException e) { + throw new RuntimeSQLException(e); + } finally { + close(rs); + close(stmt); + } + return null; + } + +} diff --git a/src/main/java/net/sf/jeasyorm/RuntimeSQLException.java b/src/main/java/net/sf/jeasyorm/RuntimeSQLException.java new file mode 100755 index 0000000..b855187 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/RuntimeSQLException.java @@ -0,0 +1,19 @@ +package net.sf.jeasyorm; + +public final class RuntimeSQLException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public RuntimeSQLException(final Throwable cause) { + super(cause); + } + + public RuntimeSQLException(final String message) { + super(message); + } + + public RuntimeSQLException(final String message, final Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/net/sf/jeasyorm/SimpleNameGuesser.java b/src/main/java/net/sf/jeasyorm/SimpleNameGuesser.java new file mode 100755 index 0000000..bb73a63 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/SimpleNameGuesser.java @@ -0,0 +1,40 @@ +package net.sf.jeasyorm; + +public class SimpleNameGuesser implements NameGuesser { + + @Override + public String[] guessTableName(Class entityClass) { + String name1 = entityClass.getSimpleName(); + String name2 = name1.replaceAll("([a-z])([A-Z])", "$1_$2"); + if (name1.equals(name2)) { + return new String[] { + name1.toUpperCase(), + "T" + name1.toUpperCase(), + }; + } else { + return new String[] { + name1.toUpperCase(), + name2.toUpperCase(), + "T" + name1.toUpperCase(), + "T" + name2.toUpperCase() + }; + } + } + + @Override + public String[] guessColumnName(Class entityClass, String field) { + String name1 = field; + String name2 = name1.replaceAll("([a-z])([A-Z])", "$1_$2"); + if (name1.equals(name2)) { + return new String[] { + name1.toUpperCase() + }; + } else { + return new String[] { + name1.toUpperCase(), + name2.toUpperCase() + }; + } + } + +} diff --git a/src/main/java/net/sf/jeasyorm/SqlTranslator.java b/src/main/java/net/sf/jeasyorm/SqlTranslator.java new file mode 100755 index 0000000..e6a6889 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/SqlTranslator.java @@ -0,0 +1,7 @@ +package net.sf.jeasyorm; + +public interface SqlTranslator { + + public String getTranslatedSql(String sql); + +} diff --git a/src/main/java/net/sf/jeasyorm/Utils.java b/src/main/java/net/sf/jeasyorm/Utils.java new file mode 100755 index 0000000..f982fb7 --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/Utils.java @@ -0,0 +1,109 @@ +package net.sf.jeasyorm; + +import java.io.BufferedReader; +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.SQLException; + +public abstract class Utils { + + public static String join(String[] arr, String sep) { + StringBuffer sb = new StringBuffer(); + for (String s : arr) { + if (sb.length() > 0) sb.append(sep); + sb.append(s); + } + return sb.toString(); + } + + /** + * Returns true if the provided class is a type supported natively (as + * opposed to a bean). + * + * @param type {@link java.lang.Class} type to be tested + * @since 1.0 + */ + public static boolean isNativeType(final Class type) { + return type == boolean.class || type == Boolean.class || + type == byte.class || type == Byte.class || + type == short.class || type == Short.class || + type == int.class || type == Integer.class || + type == long.class || type == Long.class || + type == float.class || type == Float.class || + type == double.class || type == Double.class || + type == char.class || type == Character.class || + type == byte[].class || + type == char[].class || + type == String.class || + type == BigDecimal.class || + type == java.util.Date.class || type == java.sql.Date.class || + type == java.sql.Time.class || type == java.sql.Timestamp.class || + java.sql.Clob.class.isAssignableFrom(type) || + java.sql.Blob.class.isAssignableFrom(type) || + type == Object.class; + } + + public static Object convertTo(Object value, final Class type) { + if (value == null || value.getClass() == type) { + return value; + } else if (value instanceof Number && Number.class.isAssignableFrom(type)) { + Number n = (Number) value; + if (type == Byte.class) { + return n.byteValue(); + } else if (type == Short.class) { + return n.shortValue(); + } else if (type == Integer.class) { + return n.intValue(); + } else if (type == Long.class) { + return n.longValue(); + } else if (type == Float.class) { + return n.floatValue(); + } else if (type == Double.class) { + return n.doubleValue(); + } + } else if (value instanceof java.util.Date && java.util.Date.class.isAssignableFrom(type)) { + java.util.Date d = (java.util.Date) value; + if (type == java.util.Date.class) { + return new java.util.Date(d.getTime()); + } else if (type == java.sql.Date.class) { + return new java.sql.Date(d.getTime()); + } else if (type == java.sql.Time.class) { + return new java.sql.Time(d.getTime()); + } else if (type == java.sql.Timestamp.class) { + return new java.sql.Timestamp(d.getTime()); + } + } + return value; + } + + public static int executeScript(Connection connection, BufferedReader reader, boolean ignoreException) + throws IOException, SQLException { + int num = 0; + StringBuffer sb = new StringBuffer(); + String line; + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (!"".equals(line)) { + if (sb.length() > 0) sb.append(" "); + if (line.endsWith(";")) { + sb.append(line.substring(0, line.length()-1)); + if (!ignoreException) { + num += connection.createStatement().execute(sb.toString()) ? 1 : 0; + } else { + try { + num += connection.createStatement().execute(sb.toString()) ? 1 : 0; + } catch (SQLException e) { + e = e; + } + } + sb.delete(0, sb.length()); + } else { + sb.append(line); + } + } + } + return num; + } + +} diff --git a/src/main/java/net/sf/jeasyorm/annotation/Column.java b/src/main/java/net/sf/jeasyorm/annotation/Column.java new file mode 100755 index 0000000..36fab5e --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/annotation/Column.java @@ -0,0 +1,14 @@ +package net.sf.jeasyorm.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.FIELD }) +public @interface Column { + + String name() default ""; + +} diff --git a/src/main/java/net/sf/jeasyorm/annotation/Table.java b/src/main/java/net/sf/jeasyorm/annotation/Table.java new file mode 100755 index 0000000..2028dab --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/annotation/Table.java @@ -0,0 +1,15 @@ +package net.sf.jeasyorm.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Table { + + String schema() default ""; + String name() default ""; + +} diff --git a/src/main/java/net/sf/jeasyorm/annotation/Transient.java b/src/main/java/net/sf/jeasyorm/annotation/Transient.java new file mode 100755 index 0000000..e5df86b --- /dev/null +++ b/src/main/java/net/sf/jeasyorm/annotation/Transient.java @@ -0,0 +1,12 @@ +package net.sf.jeasyorm.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD }) +public @interface Transient { + +}