| 1 3 package net.sf.persist; 4 5 import java.io.IOException ; 6 import java.lang.reflect.Method ; 7 import java.math.BigDecimal ; 8 import java.sql.Blob ; 9 import java.sql.Clob ; 10 import java.sql.Connection ; 11 import java.sql.ParameterMetaData ; 12 import java.sql.PreparedStatement ; 13 import java.sql.ResultSet ; 14 import java.sql.ResultSetMetaData ; 15 import java.sql.SQLException ; 16 import java.util.ArrayList ; 17 import java.util.Arrays ; 18 import java.util.Iterator ; 19 import java.util.LinkedHashMap ; 20 import java.util.List ; 21 import java.util.Map ; 22 import java.util.concurrent.ConcurrentHashMap ; 23 import java.util.concurrent.ConcurrentMap ; 24 25 58 public final class Persist { 59 60 private Connection connection; 61 private boolean updateAutoGeneratedKeys = false; 62 private PreparedStatement lastPreparedStatement = null; 63 private boolean closePreparedStatementsAfterRead = true; 64 65 private static ConcurrentMap <String , ConcurrentMap <Class , Mapping>> mappingCaches = new ConcurrentHashMap (); 66 private static ConcurrentMap <String , NameGuesser> nameGuessers = new ConcurrentHashMap (); 67 68 private static final String DEFAULT_CACHE = "default cache"; 69 70 private String cacheName = DEFAULT_CACHE; 71 private NameGuesser nameGuesser = null; 72 73 static { 74 mappingCaches.put(DEFAULT_CACHE, new ConcurrentHashMap ()); 75 nameGuessers.put(DEFAULT_CACHE, new DefaultNameGuesser()); 76 77 if (Log.isDebugEnabled(Log.ENGINE)) { 78 Log.debug(Log.ENGINE, "Caches initialized"); 79 } 80 } 81 82 84 91 public Persist(Connection connection) { 92 this(DEFAULT_CACHE, connection); 93 } 94 95 103 public Persist(String cacheName, Connection connection) { 104 105 if (cacheName == null) { 106 cacheName = DEFAULT_CACHE; 107 } 108 109 this.cacheName = cacheName; 110 this.connection = connection; 111 112 this.nameGuesser = nameGuessers.get(cacheName); 113 if (this.nameGuesser == null) { 114 this.nameGuesser = new DefaultNameGuesser(); 117 nameGuessers.put(cacheName, this.nameGuesser); 118 } 119 120 if (Log.isDebugEnabled(Log.ENGINE)) { 121 Log.debug(Log.ENGINE, "New instance for cache [" + cacheName + "] and connection [" + connection + "]"); 122 } 123 } 124 125 127 134 public static void setNameGuesser(final String cacheName, final NameGuesser nameGuesser) { 135 nameGuessers.put(cacheName, nameGuesser); 136 137 mappingCaches.put(cacheName, new ConcurrentHashMap ()); 139 140 if (Log.isDebugEnabled(Log.ENGINE)) { 141 Log.debug(Log.ENGINE, "Name guesser set for cache [" + cacheName + "]"); 142 } 143 } 144 145 151 public static void setNameGuesser(final NameGuesser nameGuesser) { 152 nameGuessers.put(DEFAULT_CACHE, nameGuesser); 153 } 154 155 157 165 public void setUpdateAutoGeneratedKeys(final boolean updateAutoGeneratedKeys) { 166 this.updateAutoGeneratedKeys = updateAutoGeneratedKeys; 167 168 if (Log.isDebugEnabled(Log.ENGINE)) { 169 Log.debug(Log.ENGINE, "setUpdateAutoGeneratedKeys(" + updateAutoGeneratedKeys + ")"); 170 } 171 } 172 173 176 public boolean isUpdateAutoGeneratedKeys() { 177 return updateAutoGeneratedKeys; 178 } 179 180 182 189 public Mapping getMapping(final Class objectClass) { 190 191 if (cacheName == null) { 192 cacheName = DEFAULT_CACHE; 193 } 194 195 if (!mappingCaches.containsKey(cacheName)) { 196 mappingCaches.put(cacheName, new ConcurrentHashMap ()); 199 } 200 201 final ConcurrentMap <Class , Mapping> mappingCache = mappingCaches.get(cacheName); 202 203 if (!mappingCache.containsKey(objectClass)) { 204 try { 205 mappingCache.put(objectClass, Mapping.getMapping(connection.getMetaData(), objectClass, nameGuesser)); 209 210 if (Log.isDebugEnabled(Log.ENGINE)) { 211 Log.debug(Log.ENGINE, "Cached mapping for [" + objectClass.getCanonicalName() + "]"); 212 } 213 } catch (SQLException e) { 214 throw new RuntimeSQLException(e); 215 } 216 } 217 218 return mappingCache.get(objectClass); 219 } 220 221 226 private TableMapping getTableMapping(Class objectClass, String callingMethodName) { 227 final Mapping mapping = getMapping(objectClass); 228 if (!(mapping instanceof TableMapping)) { 229 throw new RuntimeSQLException("Class [" + objectClass.getCanonicalName() 230 + "] has a @NoTable annotation defined, therefore " + callingMethodName + " can't work with it. " 231 + "If this class is supposed to be mapped to a table, @NoTable should not be used."); 232 } 233 return (TableMapping) mapping; 234 } 235 236 238 243 public Connection getConnection() { 244 return connection; 245 } 246 247 254 public void commit() { 255 try { 256 connection.commit(); 257 258 if (Log.isDebugEnabled(Log.ENGINE)) { 259 Log.debug(Log.ENGINE, "Connection commited"); 260 } 261 } catch (SQLException e) { 262 throw new RuntimeSQLException(e); 263 } 264 } 265 266 273 public void rollback() { 274 try { 275 connection.rollback(); 276 277 if (Log.isDebugEnabled(Log.ENGINE)) { 278 Log.debug(Log.ENGINE, "Connection rolled back"); 279 } 280 } catch (SQLException e) { 281 throw new RuntimeSQLException(e); 282 } 283 } 284 285 292 public void setAutoCommit(final boolean autoCommit) { 293 try { 294 connection.setAutoCommit(autoCommit); 295 296 if (Log.isDebugEnabled(Log.ENGINE)) { 297 Log.debug(Log.ENGINE, "Connection setAutoCommit(" + autoCommit + ")"); 298 } 299 } catch (SQLException e) { 300 throw new RuntimeSQLException(e); 301 } 302 } 303 304 306 317 public PreparedStatement getPreparedStatement(final String sql, final String [] autoGeneratedKeys) { 318 try { 319 if (autoGeneratedKeys == null || autoGeneratedKeys.length == 0) { 320 lastPreparedStatement = getPreparedStatement(sql); 321 } else { 322 lastPreparedStatement = connection.prepareStatement(sql, autoGeneratedKeys); 323 } 324 } catch (SQLException e) { 325 throw new RuntimeSQLException("Error creating prepared statement for sql [" + sql 326 + "] with autoGeneratedKeys " + Arrays.toString(autoGeneratedKeys) + ": " + e.getMessage(), e); 327 } 328 329 if (Log.isDebugEnabled(Log.ENGINE)) { 330 Log.debug(Log.ENGINE, "Generated PreparedStatement [" + lastPreparedStatement + "] for [" + sql 331 + "] using autoGeneratedKeys " + Arrays.toString(autoGeneratedKeys)); 332 } 333 334 return lastPreparedStatement; 335 } 336 337 344 public PreparedStatement getPreparedStatement(final String sql) { 345 346 try { 347 lastPreparedStatement = connection.prepareStatement(sql); 348 } catch (SQLException e) { 349 throw new RuntimeSQLException("Error creating prepared statement for sql [" + sql + "]: " + e.getMessage(), 350 e); 351 } 352 353 if (Log.isDebugEnabled(Log.ENGINE)) { 354 Log.debug(Log.ENGINE, "Generated PreparedStatement [" + lastPreparedStatement + "] for [" + sql + "]"); 355 } 356 357 return lastPreparedStatement; 358 } 359 360 367 public void closePreparedStatement(final PreparedStatement statement) { 368 try { 369 statement.close(); 370 } catch (SQLException e) { 371 throw new RuntimeSQLException("Error closing prepared statement: " + e.getMessage(), e); 372 } 373 374 if (Log.isDebugEnabled(Log.ENGINE)) { 375 Log.debug(Log.ENGINE, "Closed PreparedStatement [" + statement + "]"); 376 } 377 378 lastPreparedStatement = null; 379 } 380 381 386 public PreparedStatement getLastPreparedStatement() { 387 return lastPreparedStatement; 388 } 389 390 396 public void closeLastPreparedStatement() { 397 closePreparedStatement(lastPreparedStatement); 398 } 399 400 416 public void setClosePreparedStatementsAfterRead(final boolean closePreparedStatementsAfterRead) { 417 this.closePreparedStatementsAfterRead = closePreparedStatementsAfterRead; 418 419 if (Log.isDebugEnabled(Log.ENGINE)) { 420 Log.debug(Log.ENGINE, "setClosePreparedStatementsAfterRead(" + closePreparedStatementsAfterRead + ")"); 421 } 422 } 423 424 430 public boolean isClosePreparedStatementsAfterRead() { 431 return this.closePreparedStatementsAfterRead; 432 } 433 434 436 474 public static void setParameters(final PreparedStatement stmt, final Object [] parameters) { 475 476 if (parameters == null || parameters.length == 0) { 478 return; 479 } 480 481 ParameterMetaData stmtMetaData = null; 482 483 for (int i = 1; i <= parameters.length; i++) { 484 485 final Object parameter = parameters[i - 1]; 486 487 if (parameter == null) { 488 489 if (stmtMetaData == null) { 491 try { 492 stmtMetaData = stmt.getParameterMetaData(); 493 } catch (SQLException e) { 494 throw new RuntimeException (e); 495 } 496 } 497 498 int sqlType; 500 try { 501 sqlType = stmtMetaData.getParameterType(i); 502 } catch (SQLException e2) { 503 sqlType = java.sql.Types.NULL; 505 } 506 507 try { 508 stmt.setNull(i, sqlType); 509 } catch (SQLException e) { 510 throw new RuntimeSQLException("Could not set null into parameter [" + i 511 + "] using java.sql.Types [" + Log.sqlTypeToString(sqlType) + "] " + e.getMessage(), e); 512 } 513 514 if (Log.isDebugEnabled(Log.PARAMETERS)) { 515 Log.debug(Log.PARAMETERS, "Parameter [" + i + "] from PreparedStatement [" + stmt 516 + "] set to [null] using java.sql.Types [" + Log.sqlTypeToString(sqlType) + "]"); 517 } 518 519 continue; 520 } 521 522 try { 523 524 final Class type = parameter.getClass(); 525 526 if (type == Boolean .class || type == boolean.class) { 527 stmt.setBoolean(i, (Boolean ) parameter); 528 } else if (type == Byte .class || type == byte.class) { 529 stmt.setByte(i, (Byte ) parameter); 530 } else if (type == Short .class || type == short.class) { 531 stmt.setShort(i, (Short ) parameter); 532 } else if (type == Integer .class || type == int.class) { 533 stmt.setInt(i, (Integer ) parameter); 534 } else if (type == Long .class || type == long.class) { 535 stmt.setLong(i, (Long ) parameter); 536 } else if (type == Float .class || type == float.class) { 537 stmt.setFloat(i, (Float ) parameter); 538 } else if (type == Double .class || type == double.class) { 539 stmt.setDouble(i, (Double ) parameter); 540 } else if (type == Character .class || type == char.class) { 541 stmt.setString(i, parameter == null ? null : "" + (Character ) parameter); 542 } else if (type == char[].class) { 543 stmt.setString(i, parameter == null ? null : new String ((char[]) parameter)); 545 } else if (type == Character [].class) { 546 final Character [] src = (Character []) parameter; 548 final char[] dst = new char[src.length]; 549 for (int j = 0; j < src.length; j++) { dst[j] = src[j]; 551 } 552 stmt.setString(i, new String (dst)); 553 } else if (type == String .class) { 554 stmt.setString(i, (String ) parameter); 555 } else if (type == BigDecimal .class) { 556 stmt.setBigDecimal(i, (BigDecimal ) parameter); 557 } else if (type == byte[].class) { 558 stmt.setBytes(i, (byte[]) parameter); 559 } else if (type == Byte [].class) { 560 final Byte [] src = (Byte []) parameter; 562 final byte[] dst = new byte[src.length]; 563 for (int j = 0; j < src.length; j++) { dst[j] = src[j]; 565 } 566 stmt.setBytes(i, dst); 567 } else if (parameter instanceof java.io.Reader ) { 568 final java.io.Reader reader = (java.io.Reader ) parameter; 569 570 int size = 0; 575 try { 576 reader.reset(); 577 while (reader.read() != -1) { 578 size++; 579 } 580 reader.reset(); 581 } catch (IOException e) { 582 throw new RuntimeIOException(e); 583 } 584 stmt.setCharacterStream(i, reader, size); 585 } else if (parameter instanceof java.io.InputStream ) { 586 final java.io.InputStream inputStream = (java.io.InputStream ) parameter; 587 588 int size = 0; 593 try { 594 inputStream.reset(); 595 while (inputStream.read() != -1) { 596 size++; 597 } 598 inputStream.reset(); 599 } catch (IOException e) { 600 throw new RuntimeIOException(e); 601 } 602 stmt.setBinaryStream(i, inputStream, size); 603 } else if (parameter instanceof Clob ) { 604 stmt.setClob(i, (Clob ) parameter); 605 } else if (parameter instanceof Blob ) { 606 stmt.setBlob(i, (Blob ) parameter); 607 } else if (type == java.util.Date .class) { 608 final java.util.Date date = (java.util.Date ) parameter; 609 stmt.setTimestamp(i, new java.sql.Timestamp (date.getTime())); 610 } else if (type == java.sql.Date .class) { 611 stmt.setDate(i, (java.sql.Date ) parameter); 612 } else if (type == java.sql.Time .class) { 613 stmt.setTime(i, (java.sql.Time ) parameter); 614 } else if (type == java.sql.Timestamp .class) { 615 stmt.setTimestamp(i, (java.sql.Timestamp ) parameter); 616 } else { 617 stmt.setObject(i, parameter); 620 } 621 622 if (Log.isDebugEnabled(Log.PARAMETERS)) { 623 Log.debug(Log.PARAMETERS, "PreparedStatement [" + stmt + "] Parameter [" + i + "] type [" 624 + type.getSimpleName() + "] set to [" + Log.objectToString(parameter) + "]"); 625 } 626 627 } catch (SQLException e) { 628 throw new RuntimeSQLException(e); 629 } 630 } 631 } 632 633 640 private static boolean isNativeType(final Class type) { 641 642 644 return (type == boolean.class || type == Boolean .class || type == byte.class || type == Byte .class 645 || type == short.class || type == Short .class || type == int.class || type == Integer .class 646 || type == long.class || type == Long .class || type == float.class || type == Float .class 647 || type == double.class || type == Double .class || type == char.class || type == Character .class 648 || type == byte[].class || type == Byte [].class || type == char[].class || type == Character [].class 649 || type == String .class || type == BigDecimal .class || type == java.util.Date .class 650 || type == java.sql.Date .class || type == java.sql.Time .class || type == java.sql.Timestamp .class 651 || type == java.io.InputStream .class || type == java.io.Reader .class || type == java.sql.Clob .class 652 || type == java.sql.Blob .class || type == Object .class); 653 } 654 655 699 public static Object getValueFromResultSet(final ResultSet resultSet, final int column, final Class type) { 700 701 Object value = null; 702 703 try { 704 705 if (type == boolean.class) { 706 value = resultSet.getBoolean(column); 707 } else if (type == Boolean .class) { 708 value = resultSet.getObject(column) == null ? null : resultSet.getBoolean(column); 709 } else if (type == byte.class) { 710 value = resultSet.getByte(column); 711 } else if (type == Byte .class) { 712 value = resultSet.getObject(column) == null ? null : resultSet.getByte(column); 713 } else if (type == short.class) { 714 value = resultSet.getShort(column); 715 } else if (type == Short .class) { 716 value = resultSet.getObject(column) == null ? null : resultSet.getShort(column); 717 } else if (type == int.class) { 718 value = resultSet.getInt(column); 719 } else if (type == Integer .class) { 720 value = resultSet.getObject(column) == null ? null : resultSet.getInt(column); 721 } else if (type == long.class) { 722 value = resultSet.getLong(column); 723 } else if (type == Long .class) { 724 value = resultSet.getObject(column) == null ? null : resultSet.getLong(column); 725 } else if (type == float.class) { 726 value = resultSet.getFloat(column); 727 } else if (type == Float .class) { 728 value = resultSet.getObject(column) == null ? null : resultSet.getFloat(column); 729 } else if (type == double.class) { 730 value = resultSet.getDouble(column); 731 } else if (type == Double .class) { 732 value = resultSet.getObject(column) == null ? null : resultSet.getDouble(column); 733 } else if (type == BigDecimal .class) { 734 value = resultSet.getObject(column) == null ? null : resultSet.getBigDecimal(column); 735 } else if (type == String .class) { 736 value = resultSet.getString(column); 737 } else if (type == Character .class || type == char.class) { 738 final String str = resultSet.getString(column); 739 if (str != null && str.length() > 1) { 740 throw new RuntimeSQLException("Column [" + column + "] returned a string with length [" 741 + str.length() + "] but field type [" + type.getSimpleName() 742 + "] can only accept 1 character"); 743 } 744 value = (str == null || str.length() == 0) ? null : str.charAt(0); 745 } else if (type == byte[].class || type == Byte [].class) { 746 value = resultSet.getBytes(column); 747 } else if (type == char[].class || type == Character [].class) { 748 final String str = resultSet.getString(column); 749 value = (str == null) ? null : str.toCharArray(); 750 } else if (type == java.util.Date .class) { 751 final java.sql.Timestamp timestamp = resultSet.getTimestamp(column); 752 value = (timestamp == null) ? null : new java.util.Date (timestamp.getTime()); 753 } else if (type == java.sql.Date .class) { 754 value = resultSet.getDate(column); 755 } else if (type == java.sql.Time .class) { 756 value = resultSet.getTime(column); 757 } else if (type == java.sql.Timestamp .class) { 758 value = resultSet.getTimestamp(column); 759 } else if (type == java.io.InputStream .class) { 760 value = resultSet.getBinaryStream(column); 761 } else if (type == java.io.Reader .class) { 762 value = resultSet.getCharacterStream(column); 763 } else if (type == java.sql.Clob .class) { 764 value = resultSet.getClob(column); 765 } else if (type == java.sql.Blob .class) { 766 value = resultSet.getBlob(column); 767 } else { 768 value = resultSet.getObject(column); 770 } 771 772 } catch (SQLException e) { 773 throw new RuntimeSQLException(e); 774 } 775 776 if (Log.isDebugEnabled(Log.RESULTS)) { 777 Log.debug(Log.RESULTS, "Read ResultSet [" + resultSet + "] column [" + column + "]" 778 + (value == null ? "" : " type [" + value.getClass().getSimpleName() + "]") + " value [" 779 + Log.objectToString(value) + "]"); 780 } 781 782 return value; 783 } 784 785 840 public static Object getValueFromResultSet(final ResultSet resultSet, final int column, final int type) { 841 842 Object value = null; 843 844 try { 845 846 if (type == java.sql.Types.ARRAY) { 847 value = resultSet.getArray(column); 848 } else if (type == java.sql.Types.BIGINT) { 849 value = resultSet.getObject(column) == null ? null : resultSet.getLong(column); 850 } else if (type == java.sql.Types.BINARY) { 851 value = resultSet.getBytes(column); 852 } else if (type == java.sql.Types.BIT) { 853 value = resultSet.getObject(column) == null ? null : resultSet.getBoolean(column); 854 } else if (type == java.sql.Types.BLOB) { 855 value = resultSet.getBytes(column); 856 } else if (type == java.sql.Types.BOOLEAN) { 857 value = resultSet.getObject(column) == null ? null : resultSet.getBoolean(column); 858 } else if (type == java.sql.Types.CHAR) { 859 value = resultSet.getString(column); 860 } else if (type == java.sql.Types.CLOB) { 861 value = resultSet.getString(column); 862 } else if (type == java.sql.Types.DATALINK) { 863 value = resultSet.getBinaryStream(column); 864 } else if (type == java.sql.Types.DATE) { 865 value = resultSet.getDate(column); 866 } else if (type == java.sql.Types.DECIMAL) { 867 value = resultSet.getBigDecimal(column); 868 } else if (type == java.sql.Types.DOUBLE) { 869 value = resultSet.getObject(column) == null ? null : resultSet.getDouble(column); 870 } else if (type == java.sql.Types.FLOAT) { 871 value = resultSet.getObject(column) == null ? null : resultSet.getFloat(column); 872 } else if (type == java.sql.Types.INTEGER) { 873 value = resultSet.getObject(column) == null ? null : resultSet.getInt(column); 874 } else if (type == java.sql.Types.JAVA_OBJECT) { 875 value = resultSet.getObject(column); 876 } else if (type == java.sql.Types.LONGVARBINARY) { 877 value = resultSet.getBytes(column); 878 } else if (type == java.sql.Types.LONGVARCHAR) { 879 value = resultSet.getString(column); 880 } else if (type == java.sql.Types.NULL) { 881 value = null; 882 } else if (type == java.sql.Types.NUMERIC) { 883 value = resultSet.getBigDecimal(column); 884 } else if (type == java.sql.Types.OTHER) { 885 value = resultSet.getObject(column); 886 } else if (type == java.sql.Types.REAL) { 887 value = resultSet.getObject(column) == null ? null : resultSet.getDouble(column); 888 } else if (type == java.sql.Types.REF) { 889 value = resultSet.getRef(column); 890 } else if (type == java.sql.Types.SMALLINT) { 891 value = resultSet.getObject(column) == null ? null : resultSet.getInt(column); 892 } else if (type == java.sql.Types.TIME) { 893 value = resultSet.getTime(column); 894 } else if (type == java.sql.Types.TIMESTAMP) { 895 value = resultSet.getTimestamp(column); 896 } else if (type == java.sql.Types.TINYINT) { 897 value = resultSet.getObject(column) == null ? null : resultSet.getInt(column); 898 } else if (type == java.sql.Types.VARBINARY) { 899 value = resultSet.getBytes(column); 900 } else if (type == java.sql.Types.VARCHAR) { 901 value = resultSet.getString(column); 902 } 903 904 else if (type == 100) { 906 value = resultSet.getObject(column) == null ? null : resultSet.getFloat(column); 907 } else if (type == 101) { 908 value = resultSet.getObject(column) == null ? null : resultSet.getDouble(column); 909 } 910 911 else { 912 throw new RuntimeSQLException("Could not get value for result set using type [" 913 + Log.sqlTypeToString(type) + "] on column [" + column + "]"); 914 } 915 916 } catch (SQLException e) { 917 throw new RuntimeSQLException(e); 918 } 919 920 if (Log.isDebugEnabled(Log.RESULTS)) { 921 Log.debug(Log.RESULTS, "Read ResultSet [" + resultSet + "] column [" + column + "] sql type [" 922 + Log.sqlTypeToString(type) + "]" 923 + (value == null ? "" : " type [" + value.getClass().getSimpleName() + "]") + " value [" 924 + Log.objectToString(value) + "]"); 925 } 926 927 return value; 928 } 929 930 939 private static Object [] getParametersFromObject(final Object object, final String [] columns, 940 final TableMapping mapping) { 941 942 Object [] parameters = new Object [columns.length]; 943 for (int i = 0; i < columns.length; i++) { 944 final String columnName = columns[i]; 945 final Method getter = mapping.getGetterForColumn(columnName); 946 947 Object value = null; 948 try { 949 value = getter.invoke(object, new Object [] {}); 950 } catch (Exception e) { 951 throw new RuntimeSQLException("Could not access getter for column [" + columnName + "]", e); 952 } 953 954 parameters[i] = value; 955 } 956 957 return parameters; 958 } 959 960 974 public Object loadObject(final Class objectClass, final ResultSet resultSet) throws SQLException { 975 976 final ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); 977 978 Object ret = null; 979 980 if (isNativeType(objectClass)) { 982 if (resultSetMetaData.getColumnCount() != 1) { 983 throw new RuntimeSQLException("ResultSet returned [" + resultSetMetaData.getColumnCount() 984 + "] columns but 1 column was expected to load data into an instance of [" 985 + objectClass.getName() + "]"); 986 } 987 ret = getValueFromResultSet(resultSet, 1, objectClass); 988 } 989 990 else { 992 993 final Mapping mapping = getMapping(objectClass); 994 995 try { 996 ret = objectClass.newInstance(); 997 } catch (Exception e) { 998 throw new RuntimeSQLException(e); 999 } 1000 1001 for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { 1002 final String columnName = resultSetMetaData.getColumnName(i).toLowerCase(); 1003 final Method setter = mapping.getSetterForColumn(columnName); 1004 if (setter == null) { 1005 throw new RuntimeSQLException("Column [" + columnName 1006 + "] from result set does not have a mapping to a field in [" 1007 + objectClass.getName() + "]"); 1008 } 1009 1010 final Class type = setter.getParameterTypes()[0]; 1011 final Object value = getValueFromResultSet(resultSet, i, type); 1012 1013 try { 1014 setter.invoke(ret, new Object [] { value }); 1015 } catch (Exception e) { 1016 throw new RuntimeSQLException("Error setting value [" + value + "]" 1017 + (value == null ? "" : " of type [" + value.getClass().getName() + "]") + " from column [" 1018 + columnName + "] using setter [" + setter + "]: " + e.getMessage(), e); 1019 } 1020 } 1021 1022 } 1023 1024 return ret; 1025 } 1026 1027 1039 public static Map <String , Object > loadMap(final ResultSet resultSet) throws SQLException { 1040 1041 final Map ret = new LinkedHashMap (); 1042 final ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); 1043 1044 for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { 1045 final String columnName = resultSetMetaData.getColumnName(i).toLowerCase(); 1046 final int type = resultSetMetaData.getColumnType(i); 1047 final Object value = getValueFromResultSet(resultSet, i, type); 1048 ret.put(columnName, value); 1049 } 1050 1051 return ret; 1052 } 1053 1054 1063 public void setAutoGeneratedKeys(final Object object, final Result result) { 1064 1065 if (result.getGeneratedKeys().size() != 0) { 1066 final TableMapping mapping = getTableMapping(object.getClass(), "setAutoGeneratedKeys()"); 1067 for (int i = 0; i < mapping.getAutoGeneratedColumns().length; i++) { 1068 final String columnName = mapping.getAutoGeneratedColumns()[i]; 1069 final Method setter = mapping.getSetterForColumn(columnName); 1070 final Object key = result.getGeneratedKeys().get(i); 1071 try { 1072 setter.invoke(object, new Object [] { key }); 1073 } catch (Exception e) { 1074 throw new RuntimeSQLException("Could not invoke setter [" + setter + "] with auto generated key [" 1075 + key + "] of class [" + key.getClass().getName() + "]", e); 1076 } 1077 } 1078 } 1079 1080 } 1081 1082 1084 1100 public Result executeUpdate(final Class objectClass, final String sql, final String [] autoGeneratedKeys, 1101 final Object ...parameters) { 1102 1103 long begin = 0; 1104 if (Log.isDebugEnabled(Log.PROFILING)) { 1105 begin = System.currentTimeMillis(); 1106 } 1107 1108 final PreparedStatement stmt = getPreparedStatement(sql, autoGeneratedKeys); 1109 1110 setParameters(stmt, parameters); 1111 1112 int rowsModified = 0; 1113 try { 1114 rowsModified = stmt.executeUpdate(); 1115 } catch (SQLException e) { 1116 throw new RuntimeSQLException("Error executing sql [" + sql + "] with parameters " 1117 + Arrays.toString(parameters) + ": " + e.getMessage(), e); 1118 } 1119 1120 final List generatedKeys = new ArrayList (); 1121 if (autoGeneratedKeys.length != 0) { 1122 try { 1123 final Mapping mapping = getMapping(objectClass); 1124 final ResultSet resultSet = stmt.getGeneratedKeys(); 1125 for (int i = 0; i < autoGeneratedKeys.length; i++) { 1126 resultSet.next(); 1127 1128 final Method setter = mapping.getSetterForColumn(autoGeneratedKeys[i]); 1132 final Class type = setter.getParameterTypes()[0]; 1133 final Object value = Persist.getValueFromResultSet(resultSet, 1, type); 1134 1135 generatedKeys.add(value); 1136 } 1137 resultSet.close(); 1138 } catch (SQLException e) { 1139 throw new RuntimeSQLException("This JDBC driver does not support PreparedStatement.getGeneratedKeys()." 1140 + " Please use setUpdateAutoGeneratedKeys(false) in your Persist instance" 1141 + " to disable attempts to use that feature"); 1142 } 1143 } 1144 1145 Result result = new Result(rowsModified, generatedKeys); 1146 1147 if (Log.isDebugEnabled(Log.PROFILING)) { 1148 final long end = System.currentTimeMillis(); 1149 Log.debug(Log.PROFILING, "executeUpdate in [" + (end - begin) + "ms] for sql [" + sql + "]"); 1150 } 1151 1152 return result; 1153 } 1154 1155 1165 public int executeUpdate(final String sql, final Object ...parameters) { 1166 1167 final PreparedStatement stmt = getPreparedStatement(sql); 1168 int rowsModified = 0; 1169 1170 try { 1171 setParameters(stmt, parameters); 1172 rowsModified = stmt.executeUpdate(); 1173 } catch (SQLException e) { 1174 throw new RuntimeSQLException("Error executing sql [" + sql + "] with parameters " 1175 + Arrays.toString(parameters) + ": " + e.getMessage(), e); 1176 } 1177 1178 closePreparedStatement(stmt); 1179 return rowsModified; 1180 } 1181 1182 1184 1189 public int insert(final Object object) { 1190 final TableMapping mapping = getTableMapping(object.getClass(), "insert()"); 1191 final String sql = mapping.getInsertSql(); 1192 final String [] columns = mapping.getNotAutoGeneratedColumns(); 1193 final Object [] parameters = getParametersFromObject(object, columns, mapping); 1194 1195 int ret = 0; 1196 if (updateAutoGeneratedKeys) { 1197 if (mapping.supportsGetGeneratedKeys()) { 1198 final Result result = executeUpdate(object.getClass(), sql, mapping.getAutoGeneratedColumns(), 1199 parameters); 1200 setAutoGeneratedKeys(object, result); 1201 ret = result.getRowsModified(); 1202 } else { 1203 throw new RuntimeSQLException("While inserting instance of [" + object.getClass().getName() 1204 + "] autoUpdateGeneratedKeys is set to [true] but the database doesn't support this feature"); 1205 } 1206 } else { 1207 ret = executeUpdate(sql, parameters); 1208 } 1209 return ret; 1210 } 1211 1212 1217 public int[] insertBatch(final Object ...objects) { 1219 if (objects == null || objects.length == 0) { 1220 return new int[0]; 1221 } 1222 final int[] results = new int[objects.length]; 1223 for (int i = 0; i < objects.length; i++) { 1224 results[i] = insert(objects[i]); 1225 } 1226 return results; 1227 } 1228 1229 1231 1238 public int update(final Object object) { 1239 final TableMapping mapping = getTableMapping(object.getClass(), "update()"); 1240 1241 if (mapping.getPrimaryKeys().length == 0) { 1242 throw new RuntimeSQLException("Table " + mapping.getTableName() + " doesn't have a primary key"); 1243 } 1244 final String sql = mapping.getUpdateSql(); 1245 final String [] columns = new String [mapping.getNotPrimaryKeys().length + mapping.getPrimaryKeys().length]; 1246 int i = 0; 1247 for (String notPrimaryKey : mapping.getNotPrimaryKeys()) { 1248 columns[i++] = notPrimaryKey; 1249 } 1250 for (String primaryKey : mapping.getPrimaryKeys()) { 1251 columns[i++] = primaryKey; 1252 } 1253 final Object [] parameters = getParametersFromObject(object, columns, mapping); 1254 return executeUpdate(sql, parameters); 1255 } 1256 1257 1265 public int[] updateBatch(final Object ...objects) { 1266 if (objects == null || objects.length == 0) { 1268 return new int[0]; 1269 } 1270 int[] results = new int[objects.length]; 1271 for (int i = 0; i < objects.length; i++) { 1272 results[i] = update(objects[i]); 1273 } 1274 return results; 1275 } 1276 1277 1279 1286 public int delete(final Object object) { 1287 final TableMapping mapping = getTableMapping(object.getClass(), "delete()"); 1288 if (mapping.getPrimaryKeys().length == 0) { 1289 throw new RuntimeSQLException("Table " + mapping.getTableName() + " doesn't have a primary key"); 1290 } 1291 final String sql = mapping.getDeleteSql(); 1292 final String [] columns = mapping.getPrimaryKeys(); 1293 final Object [] parameters = getParametersFromObject(object, columns, mapping); 1294 return executeUpdate(sql, parameters); 1295 } 1296 1297 1304 public int[] deleteBatch(final Object ...objects) { 1305 if (objects == null || objects.length == 0) { 1307 return new int[0]; 1308 } 1309 int[] results = new int[objects.length]; 1310 for (int i = 0; i < objects.length; i++) { 1311 results[i] = delete(objects[i]); 1312 } 1313 return results; 1314 } 1315 1316 1318 1320 1329 public <T> T read(final Class <T> objectClass, final String sql) { 1330 return read(objectClass, sql, (Object []) null); 1331 } 1332 1333 1345 public <T> T read(final Class <T> objectClass, final String sql, final Object ...parameters) { 1346 final PreparedStatement stmt = getPreparedStatement(sql); 1347 return read(objectClass, stmt, parameters); 1348 } 1349 1350 1363 public <T> T read(final Class <T> objectClass, final PreparedStatement statement, final Object ...parameters) { 1364 setParameters(statement, parameters); 1365 try { 1366 final ResultSet resultSet = statement.executeQuery(); 1367 final T ret = read(objectClass, resultSet); 1368 if (closePreparedStatementsAfterRead) { 1369 closePreparedStatement(statement); 1370 } 1371 return ret; 1372 } catch (SQLException e) { 1373 throw new RuntimeSQLException(e); 1374 } 1375 } 1376 1377 1386 public <T> T read(final Class <T> objectClass, final ResultSet resultSet) { 1387 long begin = 0; 1388 if (Log.isDebugEnabled(Log.PROFILING)) { 1389 begin = System.currentTimeMillis(); 1390 } 1391 1392 Object ret = null; 1393 try { 1394 if (resultSet.next()) { 1395 ret = loadObject(objectClass, resultSet); 1396 if (resultSet.next()) { 1397 throw new RuntimeSQLException("Non-unique result returned"); 1398 } 1399 } 1400 } catch (SQLException e) { 1401 throw new RuntimeSQLException(e); 1402 } 1403 1404 if (Log.isDebugEnabled(Log.PROFILING)) { 1405 final long end = System.currentTimeMillis(); 1406 Log.debug(Log.PROFILING, "read in [" + (end - begin) + "ms] for object type [" 1407 + objectClass.getSimpleName() + "]"); 1408 } 1409 1410 return (T) ret; 1411 } 1412 1413 1418 public <T> T readByPrimaryKey(final Class <T> objectClass, final Object ...primaryKeyValues) { 1419 final TableMapping mapping = getTableMapping(objectClass, "readByPrimaryKey()"); 1420 final String sql = mapping.getSelectSql(); 1421 return read(objectClass, sql, primaryKeyValues); 1422 } 1423 1424 1426 1435 public <T> List <T> readList(final Class <T> objectClass, final ResultSet resultSet) { 1436 1437 long begin = 0; 1438 if (Log.isDebugEnabled(Log.PROFILING)) { 1439 begin = System.currentTimeMillis(); 1440 } 1441 1442 final List <T> ret = new ArrayList (); 1443 try { 1444 while (resultSet.next()) { 1445 ret.add((T) loadObject(objectClass, resultSet)); 1446 } 1447 } catch (SQLException e) { 1448 throw new RuntimeSQLException(e); 1449 } 1450 1451 if (Log.isDebugEnabled(Log.PROFILING)) { 1452 final long end = System.currentTimeMillis(); 1453 Log.debug(Log.PROFILING, "readList in [" + (end - begin) + "ms] for object type [" 1454 + objectClass.getSimpleName() + "]"); 1455 } 1456 1457 return ret; 1458 } 1459 1460 1473 public <T> List <T> readList(final Class <T> objectClass, final PreparedStatement statement, 1474 final Object ...parameters) { 1475 setParameters(statement, parameters); 1476 try { 1477 final ResultSet resultSet = statement.executeQuery(); 1478 return readList(objectClass, resultSet); 1479 } catch (SQLException e) { 1480 throw new RuntimeSQLException(e); 1481 } 1482 } 1483 1484 1496 public <T> List <T> readList(final Class <T> objectClass, final String sql, final Object ...parameters) { 1497 final PreparedStatement stmt = getPreparedStatement(sql); 1498 final List ret = readList(objectClass, stmt, parameters); 1499 if (closePreparedStatementsAfterRead) { 1500 closePreparedStatement(stmt); 1501 } 1502 return ret; 1503 } 1504 1505 1514 public <T> List <T> readList(final Class <T> objectClass, final String sql) { 1515 return readList(objectClass, sql, (Object []) null); 1516 } 1517 1518 1524 public <T> List <T> readList(final Class <T> objectClass) { 1525 final TableMapping mapping = getTableMapping(objectClass, "readList(Class)"); 1526 final String sql = mapping.getSelectAllSql(); 1527 return readList(objectClass, sql); 1528 } 1529 1530 1532 1541 public <T> Iterator <T> readIterator(final Class <T> objectClass, final ResultSet resultSet) { 1542 1543 long begin = 0; 1544 if (Log.isDebugEnabled(Log.PROFILING)) { 1545 begin = System.currentTimeMillis(); 1546 } 1547 1548 final ResultSetIterator i = new ResultSetIterator(this, objectClass, resultSet, ResultSetIterator.TYPE_OBJECT); 1549 1550 if (Log.isDebugEnabled(Log.PROFILING)) { 1551 final long end = System.currentTimeMillis(); 1552 Log.debug(Log.PROFILING, "readIterator in [" + (end - begin) + "ms] for object type [" 1553 + objectClass.getSimpleName() + "]"); 1554 } 1555 1556 return i; 1557 } 1558 1559 1572 public <T> Iterator <T> readIterator(final Class <T> objectClass, final PreparedStatement statement, 1573 final Object ...parameters) { 1574 setParameters(statement, parameters); 1575 try { 1576 final ResultSet resultSet = statement.executeQuery(); 1577 return readIterator(objectClass, resultSet); 1578 } catch (SQLException e) { 1579 throw new RuntimeSQLException(e); 1580 } 1581 } 1582 1583 1596 public <T> Iterator <T> readIterator(final Class <T> objectClass, final String sql, final Object ...parameters) { 1597 final PreparedStatement stmt = getPreparedStatement(sql); 1598 final Iterator ret = readIterator(objectClass, stmt, parameters); 1599 return ret; 1602 } 1603 1604 1614 public <T> Iterator <T> readIterator(final Class <T> objectClass, final String sql) { 1615 return readIterator(objectClass, sql, (Object []) null); 1616 } 1617 1618 1624 public <T> Iterator <T> readIterator(final Class <T> objectClass) { 1625 final TableMapping mapping = getTableMapping(objectClass, "readIterator(Class)"); 1626 final String sql = mapping.getSelectAllSql(); 1627 return readIterator(objectClass, sql); 1628 } 1629 1630 1632 1634 1644 public Map <String , Object > readMap(final String sql) { 1645 return readMap(sql, (Object []) null); 1646 } 1647 1648 1661 public Map <String , Object > readMap(final String sql, final Object ...parameters) { 1662 final PreparedStatement stmt = getPreparedStatement(sql); 1663 final Map <String , Object > ret = readMap(stmt, parameters); 1664 if (closePreparedStatementsAfterRead) { 1665 closePreparedStatement(stmt); 1666 } 1667 return ret; 1668 } 1669 1670 1683 public Map <String , Object > readMap(final PreparedStatement statement, final Object ...parameters) { 1684 setParameters(statement, parameters); 1685 try { 1686 final ResultSet resultSet = statement.executeQuery(); 1687 return readMap(resultSet); 1688 } catch (SQLException e) { 1689 throw new RuntimeSQLException(e); 1690 } 1691 } 1692 1693 1703 public Map <String , Object > readMap(final ResultSet resultSet) { 1704 1705 long begin = 0; 1706 if (Log.isDebugEnabled(Log.PROFILING)) { 1707 begin = System.currentTimeMillis(); 1708 } 1709 1710 Map <String , Object > ret = null; 1711 1712 try { 1713 if (resultSet.next()) { 1714 ret = loadMap(resultSet); 1715 if (resultSet.next()) { 1716 throw new RuntimeSQLException("Non-unique result returned"); 1717 } 1718 } else { 1719 ret = null; 1720 } 1721 } catch (SQLException e) { 1722 throw new RuntimeSQLException(e); 1723 } 1724 1725 if (Log.isDebugEnabled(Log.PROFILING)) { 1726 final long end = System.currentTimeMillis(); 1727 Log.debug(Log.PROFILING, "readMap in [" + (end - begin) + "ms]"); 1728 } 1729 1730 return ret; 1731 } 1732 1733 1735 1745 public List <Map <String , Object >> readMapList(final ResultSet resultSet) { 1746 1747 long begin = 0; 1748 if (Log.isDebugEnabled(Log.PROFILING)) { 1749 begin = System.currentTimeMillis(); 1750 } 1751 1752 final List ret = new ArrayList (); 1753 try { 1754 while (resultSet.next()) { 1755 ret.add(loadMap(resultSet)); 1756 } 1757 } catch (SQLException e) { 1758 throw new RuntimeSQLException(e); 1759 } 1760 1761 if (Log.isDebugEnabled(Log.PROFILING)) { 1762 final long end = System.currentTimeMillis(); 1763 Log.debug(Log.PROFILING, "readMapList [" + (end - begin) + "ms]"); 1764 } 1765 1766 return ret; 1767 } 1768 1769 1782 public List <Map <String , Object >> readMapList(final PreparedStatement statement, final Object ...parameters) { 1783 setParameters(statement, parameters); 1784 try { 1785 final ResultSet resultSet = statement.executeQuery(); 1786 return readMapList(resultSet); 1787 } catch (SQLException e) { 1788 throw new RuntimeSQLException(e); 1789 } 1790 } 1791 1792 1805 public List <Map <String , Object >> readMapList(final String sql, final Object ...parameters) { 1806 final PreparedStatement stmt = getPreparedStatement(sql); 1807 final List <Map <String , Object >> ret = readMapList(stmt, parameters); 1808 if (closePreparedStatementsAfterRead) { 1809 closePreparedStatement(stmt); 1810 } 1811 return ret; 1812 } 1813 1814 1824 public List <Map <String , Object >> readMapList(final String sql) { 1825 return readMapList(sql, (Object []) null); 1826 } 1827 1828 1830 1840 public Iterator readMapIterator(final ResultSet resultSet) { 1841 return new ResultSetIterator(this, null, resultSet, ResultSetIterator.TYPE_MAP); 1842 } 1843 1844 1858 public Iterator readMapIterator(final PreparedStatement statement, final Object ...parameters) { 1859 setParameters(statement, parameters); 1860 try { 1861 final ResultSet resultSet = statement.executeQuery(); 1862 return readMapIterator(resultSet); 1863 } catch (SQLException e) { 1864 throw new RuntimeSQLException(e); 1865 } 1866 } 1867 1868 1882 public Iterator readMapIterator(final String sql, final Object ...parameters) { 1883 1884 long begin = 0; 1885 if (Log.isDebugEnabled(Log.PROFILING)) { 1886 begin = System.currentTimeMillis(); 1887 } 1888 1889 final PreparedStatement stmt = getPreparedStatement(sql); 1890 final Iterator ret = readMapIterator(stmt, parameters); 1891 1892 if (Log.isDebugEnabled(Log.PROFILING)) { 1893 final long end = System.currentTimeMillis(); 1894 Log.debug(Log.PROFILING, "readMapIterator in [" + (end - begin) + "ms]"); 1895 } 1896 1897 return ret; 1898 } 1899 1900 1910 public Iterator readMapIterator(final String sql) { 1911 return readMapIterator(sql, (Object []) null); 1912 } 1913 1914} | Popular Tags |