original
This commit is contained in:
commit
e561389192
20 changed files with 1587 additions and 0 deletions
16
.gitignore
vendored
Normal file
16
.gitignore
vendored
Normal file
|
|
@ -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
|
||||
13
pom.xml
Executable file
13
pom.xml
Executable file
|
|
@ -0,0 +1,13 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>net.sf</groupId>
|
||||
<artifactId>jeasyorm</artifactId>
|
||||
<version>0.9.1</version>
|
||||
<packaging>jar</packaging>
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
||||
217
src/main/java/net/sf/jeasyorm/AbstractEntityManager.java
Executable file
217
src/main/java/net/sf/jeasyorm/AbstractEntityManager.java
Executable file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
456
src/main/java/net/sf/jeasyorm/BasicEntityManager.java
Executable file
456
src/main/java/net/sf/jeasyorm/BasicEntityManager.java
Executable file
|
|
@ -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> T load(Class<T> 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> T findUnique(Class<T> 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 <T> List<T> find(Class<T> 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<T> entities = new ArrayList<T>();
|
||||
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 <T> Page<T> find(Class<T> 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<T> entities = new ArrayList<T>();
|
||||
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<T>(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 <T> Iterator<T> iterator(Class<T> 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<T>(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> T insert(T entity) {
|
||||
SqlInfo info = getSqlInfo(this, entity.getClass());
|
||||
PreparedStatement stmt = null;
|
||||
try {
|
||||
List<String> columnNames = new ArrayList<String>();
|
||||
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 <T> 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 <T> 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<T> implements Iterator<T> {
|
||||
|
||||
private PreparedStatement stmt;
|
||||
private ResultSet rs;
|
||||
boolean isNative;
|
||||
private Class<T> entityClass;
|
||||
private Mapping mapping;
|
||||
boolean hasNext;
|
||||
|
||||
protected ResultSetIterator(PreparedStatement stmt, ResultSet rs, Class<T> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
5
src/main/java/net/sf/jeasyorm/Configuration.java
Executable file
5
src/main/java/net/sf/jeasyorm/Configuration.java
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
package net.sf.jeasyorm;
|
||||
|
||||
public class Configuration {
|
||||
|
||||
}
|
||||
65
src/main/java/net/sf/jeasyorm/DerbyEntityManager.java
Executable file
65
src/main/java/net/sf/jeasyorm/DerbyEntityManager.java
Executable file
|
|
@ -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 <T> Page<T> find(Class<T> 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<T> entities = new ArrayList<T>();
|
||||
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<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<T>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
144
src/main/java/net/sf/jeasyorm/EntityManager.java
Executable file
144
src/main/java/net/sf/jeasyorm/EntityManager.java
Executable file
|
|
@ -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<String, SqlInfo> infosByClassName = new HashMap<String, SqlInfo>();
|
||||
|
||||
private static List<Class<? extends EntityManager>> entityManagerClasses =
|
||||
new ArrayList<Class<? extends EntityManager>>();
|
||||
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<? extends EntityManager> emClass : entityManagerClasses) {
|
||||
try {
|
||||
Constructor<? extends EntityManager> 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<? extends EntityManager>) Class.forName(entityManagerClassName));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Class '" + entityManagerClassName + "' not found!");
|
||||
}
|
||||
}
|
||||
|
||||
public static void register(Class<? extends EntityManager> 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> T load(Class<T> entityClass, Object... pk);
|
||||
|
||||
public abstract <T> T findUnique(Class<T> entityClass, String query, Object... params);
|
||||
|
||||
public abstract <T> List<T> find(Class<T> entityClass, String query, Object... params);
|
||||
|
||||
public abstract <T> Page<T> find(Class<T> entityClass, int pageNum, int pageSize, String query, Object... params);
|
||||
|
||||
public abstract <T> Iterator<T> iterator(Class<T> entityClass, String query, Object... params);
|
||||
|
||||
public abstract int count(String query, Object... params);
|
||||
|
||||
public abstract <T> T insert(T entity);
|
||||
|
||||
public abstract <T> void update(T entity);
|
||||
|
||||
public abstract <T> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
src/main/java/net/sf/jeasyorm/HSQLDBEntityManager.java
Executable file
37
src/main/java/net/sf/jeasyorm/HSQLDBEntityManager.java
Executable file
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
271
src/main/java/net/sf/jeasyorm/Mapping.java
Executable file
271
src/main/java/net/sf/jeasyorm/Mapping.java
Executable file
|
|
@ -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<String, Mapping> mappingsByClassName = new HashMap<String, Mapping>();
|
||||
|
||||
protected Class<?> entityClass;
|
||||
protected Constructor<?> constructor;
|
||||
protected Map<String, FieldInfo> fieldsByName = new HashMap<String, FieldInfo>();
|
||||
protected Map<String, FieldInfo> fieldsByLcColumnName = new HashMap<String, FieldInfo>();
|
||||
|
||||
protected String catalogName;
|
||||
protected String schemaName;
|
||||
protected String tableName;
|
||||
protected List<ColumnInfo> columns = new ArrayList<ColumnInfo>();
|
||||
protected Map<String, ColumnInfo> columnsByLcColumnName = new HashMap<String, ColumnInfo>();
|
||||
|
||||
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<String> transientFieldNames = new HashSet<String>();
|
||||
// column names as specified with @Column annotation
|
||||
Map<String, String> columnNamesByFieldName = new HashMap<String, String>();
|
||||
// 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<FieldInfo> 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<ColumnInfo> 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; }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
9
src/main/java/net/sf/jeasyorm/NameGuesser.java
Executable file
9
src/main/java/net/sf/jeasyorm/NameGuesser.java
Executable file
|
|
@ -0,0 +1,9 @@
|
|||
package net.sf.jeasyorm;
|
||||
|
||||
public interface NameGuesser {
|
||||
|
||||
public String[] guessTableName(Class<?> entityClass);
|
||||
|
||||
public String[] guessColumnName(Class<?> entityClass, String field);
|
||||
|
||||
}
|
||||
77
src/main/java/net/sf/jeasyorm/OracleEntityManager.java
Executable file
77
src/main/java/net/sf/jeasyorm/OracleEntityManager.java
Executable file
|
|
@ -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 <T> Page<T> find(Class<T> 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<T> entities = new ArrayList<T>();
|
||||
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<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<T>(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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
25
src/main/java/net/sf/jeasyorm/Page.java
Executable file
25
src/main/java/net/sf/jeasyorm/Page.java
Executable file
|
|
@ -0,0 +1,25 @@
|
|||
package net.sf.jeasyorm;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
public class Page<T> extends ArrayList<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private int pageNum;
|
||||
private int pageSize;
|
||||
private int totalSize;
|
||||
|
||||
public Page(Collection<T> 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; }
|
||||
|
||||
}
|
||||
36
src/main/java/net/sf/jeasyorm/PostgreSQLEntityManager.java
Executable file
36
src/main/java/net/sf/jeasyorm/PostgreSQLEntityManager.java
Executable file
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/net/sf/jeasyorm/RuntimeSQLException.java
Executable file
19
src/main/java/net/sf/jeasyorm/RuntimeSQLException.java
Executable file
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
40
src/main/java/net/sf/jeasyorm/SimpleNameGuesser.java
Executable file
40
src/main/java/net/sf/jeasyorm/SimpleNameGuesser.java
Executable file
|
|
@ -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()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
7
src/main/java/net/sf/jeasyorm/SqlTranslator.java
Executable file
7
src/main/java/net/sf/jeasyorm/SqlTranslator.java
Executable file
|
|
@ -0,0 +1,7 @@
|
|||
package net.sf.jeasyorm;
|
||||
|
||||
public interface SqlTranslator {
|
||||
|
||||
public String getTranslatedSql(String sql);
|
||||
|
||||
}
|
||||
109
src/main/java/net/sf/jeasyorm/Utils.java
Executable file
109
src/main/java/net/sf/jeasyorm/Utils.java
Executable file
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
14
src/main/java/net/sf/jeasyorm/annotation/Column.java
Executable file
14
src/main/java/net/sf/jeasyorm/annotation/Column.java
Executable file
|
|
@ -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 "";
|
||||
|
||||
}
|
||||
15
src/main/java/net/sf/jeasyorm/annotation/Table.java
Executable file
15
src/main/java/net/sf/jeasyorm/annotation/Table.java
Executable file
|
|
@ -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 "";
|
||||
|
||||
}
|
||||
12
src/main/java/net/sf/jeasyorm/annotation/Transient.java
Executable file
12
src/main/java/net/sf/jeasyorm/annotation/Transient.java
Executable file
|
|
@ -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 {
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue