1 3 package net.sf.persist; 4 5 import java.lang.reflect.Method ; 6 import java.sql.DatabaseMetaData ; 7 import java.sql.ResultSet ; 8 import java.sql.SQLException ; 9 import java.util.ArrayList ; 10 import java.util.Collection ; 11 import java.util.HashSet ; 12 import java.util.LinkedHashMap ; 13 import java.util.List ; 14 import java.util.Locale ; 15 import java.util.Map ; 16 import java.util.Set ; 17 18 21 public final class TableMapping extends Mapping { 22 23 private final Class objectClass; 24 25 private final net.sf.persist.annotations.Table tableAnnotation; 26 private final String tableName; 27 28 private final String [] fields; private final Map <String , net.sf.persist.annotations.Column> annotationsMap; private final Map <String , Method > gettersMap; private final Map <String , Method > settersMap; 33 private final boolean supportsGetGeneratedKeys; 34 private final boolean supportsBatchUpdates; 35 36 private final Map <String , String > columnsMap = new LinkedHashMap (); private final String [] columns; 38 private final String [] primaryKeys; 39 private final String [] notPrimaryKeys; 40 private final String [] autoGeneratedColumns; 41 private final String [] notAutoGeneratedColumns; 42 43 private final String selectSql; 44 private final String selectAllSql; 45 private final String insertSql; 46 private final String updateSql; 47 private final String deleteSql; 48 49 public TableMapping(final DatabaseMetaData metaData, final Class objectClass, final NameGuesser nameGuesser) 50 throws SQLException { 51 52 ResultSet resultSet = null; 53 54 this.objectClass = objectClass; 56 57 supportsGetGeneratedKeys = metaData.supportsGetGeneratedKeys(); 59 60 supportsBatchUpdates = metaData.supportsBatchUpdates(); 62 63 final String databaseProductName = metaData.getDatabaseProductName(); 65 66 tableAnnotation = (net.sf.persist.annotations.Table) objectClass 68 .getAnnotation(net.sf.persist.annotations.Table.class); 69 70 String schemaPattern = null; 72 if (databaseProductName.equalsIgnoreCase("Oracle")) { 73 schemaPattern = "%"; } 75 76 tableName = getTableName(metaData, schemaPattern, objectClass, nameGuesser); 78 79 81 final List <String > columnsList = new ArrayList (); 82 resultSet = metaData.getColumns(null, schemaPattern, tableName, "%"); 83 while (resultSet.next()) { 84 final String columnName = resultSet.getString(4); 85 columnsList.add(columnName); 86 } 87 columns = toArray(columnsList); 88 89 91 final List <String > primaryKeysList = new ArrayList (); 92 resultSet = metaData.getPrimaryKeys(null, schemaPattern, tableName); 93 while (resultSet.next()) { 94 final String columnName = resultSet.getString(4); 95 primaryKeysList.add(columnName); 96 } 97 primaryKeys = toArray(primaryKeysList); 98 99 101 final List <String > notPrimaryKeysList = new ArrayList (); 102 for (String columnName : columns) { 103 if (!primaryKeysList.contains(columnName)) { 104 notPrimaryKeysList.add(columnName); 105 } 106 } 107 notPrimaryKeys = toArray(notPrimaryKeysList); 108 109 111 final Map [] fieldsMaps = getFieldsMaps(objectClass); 112 annotationsMap = fieldsMaps[0]; 113 gettersMap = fieldsMaps[1]; 114 settersMap = fieldsMaps[2]; 115 fields = toArray(gettersMap.keySet()); 116 117 120 final Set <String > autoGeneratedColumnsTemp = new HashSet (); 122 for (String fieldName : fields) { 123 final String columnName = getColumnName(objectClass, nameGuesser, annotationsMap, columnsList, tableName, 124 fieldName); 125 columnsMap.put(columnName.toLowerCase(Locale.ENGLISH), fieldName); 126 final net.sf.persist.annotations.Column annotation = annotationsMap.get(fieldName); 127 if (annotation != null && annotation.autoGenerated()) { 128 autoGeneratedColumnsTemp.add(columnName); 129 } 130 } 131 132 134 final List <String > notAutoGeneratedColumnsList = new ArrayList (); 135 final List <String > autoGeneratedColumnsList = new ArrayList (); 136 for (String columnName : columns) { 137 if (autoGeneratedColumnsTemp.contains(columnName)) { 138 autoGeneratedColumnsList.add(columnName); 139 } else { 140 notAutoGeneratedColumnsList.add(columnName); 141 } 142 } 143 notAutoGeneratedColumns = toArray(notAutoGeneratedColumnsList); 144 autoGeneratedColumns = toArray(autoGeneratedColumnsList); 145 146 148 final String allColumns = join(columns, "", ","); 149 final String noAutoColumns = join(notAutoGeneratedColumns, "", ","); 150 final String allPlaceholders = multiply("?", columns.length, ","); 151 final String noAutoPlaceholders = multiply("?", notAutoGeneratedColumns.length, ","); 152 final String where = join(primaryKeys, "=?", ","); 153 final String updateSet = join(notPrimaryKeys, "=?", ","); 154 155 157 selectSql = "select " + allColumns + " from " + tableName + " where " + where; 158 selectAllSql = "select " + allColumns + " from " + tableName; 159 160 if (autoGeneratedColumns.length == 0) { 161 insertSql = "insert into " + tableName + "(" + allColumns + ")values(" + allPlaceholders + ")"; 162 } else { 163 insertSql = "insert into " + tableName + "(" + noAutoColumns + ")values(" + noAutoPlaceholders + ")"; 164 } 165 166 updateSql = "update " + tableName + " set " + updateSet + " where " + where; 167 deleteSql = "delete from " + tableName + " where " + where; 168 169 } 170 171 173 public boolean supportsGetGeneratedKeys() { 174 return supportsGetGeneratedKeys; 175 } 176 177 public boolean supportsBatchUpdates() { 178 return supportsBatchUpdates; 179 } 180 181 public Class getObjectClass() { 182 return objectClass; 183 } 184 185 public String getTableName() { 186 return tableName; 187 } 188 189 public net.sf.persist.annotations.Table getTableAnnotation() { 190 return tableAnnotation; 191 } 192 193 public String [] getColumns() { 194 return columns; 195 } 196 197 public Map <String , String > getColumnsMap() { 198 return columnsMap; 199 } 200 201 public String [] getPrimaryKeys() { 202 return primaryKeys; 203 } 204 205 public String [] getNotPrimaryKeys() { 206 return notPrimaryKeys; 207 } 208 209 public String [] getAutoGeneratedColumns() { 210 return autoGeneratedColumns; 211 } 212 213 public String [] getNotAutoGeneratedColumns() { 214 return notAutoGeneratedColumns; 215 } 216 217 public String [] getFields() { 218 return fields; 219 } 220 221 public Map <String , net.sf.persist.annotations.Column> getAnnotationsMap() { 222 return annotationsMap; 223 } 224 225 public Map <String , Method > getGettersMap() { 226 return gettersMap; 227 } 228 229 public Map <String , Method > getSettersMap() { 230 return settersMap; 231 } 232 233 public Method getGetterForColumn(final String columnName) { 234 final String fieldName = columnsMap.get(columnName.toLowerCase(Locale.ENGLISH)); 235 return gettersMap.get(fieldName); 236 } 237 238 public Method getSetterForColumn(final String columnName) { 239 final String fieldName = columnsMap.get(columnName.toLowerCase(Locale.ENGLISH)); 240 return settersMap.get(fieldName); 241 } 242 243 public String getSelectSql() { 244 return selectSql; 245 } 246 247 public String getSelectAllSql() { 248 return selectAllSql; 249 } 250 251 public String getInsertSql() { 252 return insertSql; 253 } 254 255 public String getUpdateSql() { 256 return updateSql; 257 } 258 259 public String getDeleteSql() { 260 return deleteSql; 261 } 262 263 265 private static String getTableName(final DatabaseMetaData metaData, final String schema, final Class objectClass, 266 final NameGuesser nameGuesser) throws SQLException { 267 268 String name = null; 269 270 final net.sf.persist.annotations.Table tableAnnotation = (net.sf.persist.annotations.Table) objectClass 271 .getAnnotation(net.sf.persist.annotations.Table.class); 272 273 if (tableAnnotation != null && !tableAnnotation.name().equals("")) { 274 name = checkTableName(metaData, schema, tableAnnotation.name()); 276 277 if (name == null) { 279 throw new RuntimeSQLException("Class [" + objectClass.getName() + "] specifies table [" 280 + tableAnnotation.name() + "] that does not exist in the database"); 281 } 282 } else { 283 final String className = objectClass.getSimpleName().substring(0, 1).toLowerCase() 285 + objectClass.getSimpleName().substring(1); 286 final Set <String > guessedNames = nameGuesser.guessColumn(className); 287 for (String guessedTableName : guessedNames) { 288 name = checkTableName(metaData, schema, guessedTableName); 289 if (name != null) { 290 break; 291 } 292 } 293 if (name == null) { 294 throw new RuntimeSQLException("Class [" + objectClass.getName() 295 + "] does not specify a table name through a Table annotation and no guessed table names " 296 + guessedNames + " exist in the database"); 297 } 298 } 299 300 return name; 301 } 302 303 308 private static String checkTableName(final DatabaseMetaData metaData, final String schema, final String tableName) 309 throws SQLException { 310 311 ResultSet resultSet; 312 String ret = null; 313 314 resultSet = metaData.getTables(null, schema, tableName.toUpperCase(Locale.ENGLISH), null); 316 if (resultSet.next()) { 317 ret = tableName.toUpperCase(Locale.ENGLISH); 318 } 319 resultSet.close(); 320 321 if (ret == null) { 322 resultSet = metaData.getTables(null, schema, tableName.toLowerCase(Locale.ENGLISH), null); 324 if (resultSet.next()) { 325 ret = tableName.toLowerCase(Locale.ENGLISH); 326 } 327 resultSet.close(); 328 } 329 330 if (ret == null) { 331 resultSet = metaData.getTables(null, schema, "%", null); 335 while (resultSet.next()) { 336 final String dbTableName = resultSet.getString(3); 337 if (tableName.equalsIgnoreCase(dbTableName)) { 338 ret = dbTableName; 339 break; 340 } 341 } 342 resultSet.close(); 343 } 344 345 return ret; 346 } 347 348 private static String getColumnName(final Class objectClass, final NameGuesser nameGuesser, 349 final Map <String , net.sf.persist.annotations.Column> annotationsMap, final List <String > columnsList, 350 final String tableName, final String fieldName) throws SQLException { 351 352 String columnName = null; 353 354 final net.sf.persist.annotations.Column annotation = annotationsMap.get(fieldName); 355 if (annotation != null && !annotation.name().equals("")) { 356 columnName = getIgnoreCase(columnsList, annotation.name()); 358 359 if (columnName == null) { 361 throw new RuntimeSQLException("Field [" + fieldName + "] from class [" + objectClass.getName() 362 + "] specifies column [" + annotation.name() + "] on table [" 363 + tableName.toLowerCase(Locale.ENGLISH) + "] that does not exist in the database"); 364 } 365 } else { 366 final Set <String > guessedNames = nameGuesser.guessColumn(fieldName); 368 for (String guessedColumnName : guessedNames) { 369 columnName = getIgnoreCase(columnsList, guessedColumnName); 370 if (columnName != null) { 371 break; 372 } 373 } 374 if (columnName == null) { 375 throw new RuntimeSQLException("Field [" + fieldName + "] from class [" + objectClass.getName() 376 + "] does not specify a column name through a Column annotation and no guessed column names " 377 + guessedNames + " exist in the database. If this field is not supposed to be associated " 378 + "with the database, please annotate it with @NoColumn"); 379 } 380 } 381 382 return columnName; 383 } 384 385 387 391 private static String getIgnoreCase(final Collection <String > collection, final String str) { 392 String ret = null; 393 for (String s : collection) { 394 if (s.equalsIgnoreCase(str)) { 395 ret = s; 396 break; 397 } 398 } 399 return ret; 400 } 401 402 private static String [] toArray(final List <String > list) { 403 String [] array = new String [list.size()]; 404 for (int i = 0; i < list.size(); i++) { 405 array[i] = list.get(i); 406 } 407 return array; 408 } 409 410 private static String [] toArray(final Set <String > set) { 411 final String [] array = new String [set.size()]; 412 int i = 0; 413 for (String s : set) { 414 array[i] = s; 415 i++; 416 } 417 return array; 418 } 419 420 private static String join(final String [] list, final String suffix, final String separator) { 421 final StringBuffer buf = new StringBuffer (); 422 for (String obj : list) { 423 buf.append(obj.toString()).append(suffix).append(separator); 424 } 425 if (buf.length() > 0 && separator.length() > 0) { 426 buf.delete(buf.length() - separator.length(), buf.length()); 427 } 428 return buf.toString(); 429 } 430 431 private static String multiply(final String str, final int times, final String separator) { 432 final StringBuffer buf = new StringBuffer (); 433 for (int i = 0; i < times; i++) { 434 buf.append(str).append(separator); 435 } 436 if (separator.length() > 0) { 437 buf.delete(buf.length() - separator.length(), buf.length()); 438 } 439 return buf.toString(); 440 } 441 442 } 443 | Popular Tags |