001 /* 002 * The MIT License 003 * 004 * Copyright (c) 2012, Ninja Squad 005 * 006 * Permission is hereby granted, free of charge, to any person obtaining a copy 007 * of this software and associated documentation files (the "Software"), to deal 008 * in the Software without restriction, including without limitation the rights 009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 010 * copies of the Software, and to permit persons to whom the Software is 011 * furnished to do so, subject to the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be included in 014 * all copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 022 * THE SOFTWARE. 023 */ 024 025 package com.ninja_squad.dbsetup.bind; 026 027 import java.math.BigDecimal; 028 import java.math.BigInteger; 029 import java.sql.Date; 030 import java.sql.Time; 031 import java.sql.Timestamp; 032 import java.sql.Types; 033 034 /** 035 * Utility class allowing to get various kinds of binders. The {@link DefaultBinderConfiguration} uses binders 036 * returned by this class, based on the type of the parameter. 037 * @author JB Nizet 038 */ 039 public final class Binders { 040 041 private static final Binder DEFAULT_BINDER = new DefaultBinder(); 042 private static final Binder DATE_BINDER = new DateBinder(); 043 private static final Binder TIMESTAMP_BINDER = new TimestampBinder(); 044 private static final Binder DECIMAL_BINDER = new DecimalBinder(); 045 private static final Binder INTEGER_BINDER = new IntegerBinder(); 046 private static final Binder TIME_BINDER = new TimeBinder(); 047 private static final Binder STRING_BINDER = new StringBinder(); 048 049 private Binders() { 050 } 051 052 /** 053 * Returns the default binder, which uses <code>stmt.setObject()</code> to bind the parameter. 054 */ 055 public static Binder defaultBinder() { 056 return DEFAULT_BINDER; 057 } 058 059 /** 060 * Returns a binder suitable for columns of type CHAR and VARCHAR. The returned binder supports values of type 061 * <ul> 062 * <li><code>String</code></li> 063 * <li><code>enum</code>: the name of the enum is used as bound value</li> 064 * <li><code>Object</code>: the <code>toString()</code> of the object is used as bound value</li> 065 * </ul> 066 */ 067 public static Binder stringBinder() { 068 return STRING_BINDER; 069 } 070 071 /** 072 * Returns a binder suitable for columns of type DATE. The returned binder supports values of type 073 * <ul> 074 * <li><code>java.sql.Date</code></li> 075 * <li><code>java.util.Date</code>: the milliseconds of the date are used to construct a java.sql.Date</li> 076 * <li><code>java.util.Calendar</code>: the milliseconds of the calendar are used to construct a java.sql.Date 077 * </li> 078 * <li><code>String</code>: the string is transformed to a java.sql.Date using the <code>Date.valueOf()</code> 079 * method</li> 080 * </ul> 081 * If the value is none of these types, <code>stmt.setObject()</code> is used to bind the value. 082 */ 083 public static Binder dateBinder() { 084 return DATE_BINDER; 085 } 086 087 /** 088 * Returns a binder suitable for columns of type TIMESTAMP. The returned binder supports values of type 089 * <ul> 090 * <li><code>java.sql.Timestamp</code></li> 091 * <li><code>java.util.Date</code>: the milliseconds of the date are used to construct a java.sql.Timestamp</li> 092 * <li><code>java.util.Calendar: the milliseconds of the calendar are used to construct a 093 * java.sql.Timestamp</code></li> 094 * <li><code>String</code>: the string is transformed to a <code>java.sql.Timestamp</code> using the 095 * <code>Timestamp.valueOf()</code> method, or using the <code>java.sql.Date.valueOf()</code> method if the 096 * string has less than 19 characters</li> 097 * </ul> 098 * If the value is none of these types, <code>stmt.setObject()</code> is used to bind the value. 099 */ 100 public static Binder timestampBinder() { 101 return TIMESTAMP_BINDER; 102 } 103 104 /** 105 * Returns a binder suitable for columns of type TIME. The returned binder supports values of type 106 * <ul> 107 * <li><code>java.sql.Time</code></li> 108 * <li><code>java.util.Date</code>: the milliseconds of the date are used to construct a 109 * <code>java.sql.Time</code></li> 110 * <li><code>java.util.Calendar</code>: the milliseconds of the calendar are used to construct a 111 * <code>java.sql.Time</code> 112 * </li> 113 * <li><code>String</code>: the string is transformed to a java.sql.Time using the 114 * <code>Time.valueOf()</code> method</li> 115 * </ul> 116 * If the value is none of these types, <code>stmt.setObject()</code> is used to bind the value. 117 */ 118 public static Binder timeBinder() { 119 return TIME_BINDER; 120 } 121 122 /** 123 * Returns a binder suitable for numeric, decimal columns. The returned binder supports values of type 124 * <ul> 125 * <li><code>String</code>: the string is transformed to a java.math.BigDecimal using its constructor</li> 126 * </ul> 127 * If the value is none of these types, <code>stmt.setObject()</code> is used to bind the value. 128 */ 129 public static Binder decimalBinder() { 130 return DECIMAL_BINDER; 131 } 132 133 /** 134 * Returns a binder suitable for numeric, integer columns. The returned binder supports values of type 135 * <ul> 136 * <li><code>enum</code>: the enum is transformed into an integer by taking its ordinal</li> 137 * <li><code>String</code>: the string is transformed to a <code>java.math.BigInteger</code> using its 138 * constructor</li> 139 * </ul> 140 * If the value is none of these types, <code>stmt.setObject()</code> is used to bind the value. 141 */ 142 public static Binder integerBinder() { 143 return INTEGER_BINDER; 144 } 145 146 /** 147 * The implementation for {@link Binders#stringBinder()} 148 * @author JB Nizet 149 */ 150 private static final class StringBinder implements Binder { 151 @Override 152 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 153 if (value instanceof String) { 154 stmt.setString(param, (String) value); 155 } 156 else if (value instanceof Enum<?>) { 157 stmt.setString(param, ((Enum<?>) value).name()); 158 } 159 else if (value == null) { 160 stmt.setObject(param, null); 161 } 162 else { 163 stmt.setString(param, value.toString()); 164 } 165 } 166 167 @Override 168 public String toString() { 169 return "Binders.stringBinder"; 170 } 171 } 172 173 /** 174 * The implementation for {@link Binders#timeBinder()} 175 * @author JB Nizet 176 */ 177 private static final class TimeBinder implements Binder { 178 @Override 179 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 180 if (value instanceof Time) { 181 stmt.setTime(param, (Time) value); 182 } 183 else if (value instanceof java.util.Date) { 184 stmt.setTime(param, new Time(((java.util.Date) value).getTime())); 185 } 186 else if (value instanceof java.util.Calendar) { 187 stmt.setTime(param, new Time(((java.util.Calendar) value).getTimeInMillis())); 188 } 189 else if (value instanceof String) { 190 stmt.setTime(param, Time.valueOf((String) value)); 191 } 192 else { 193 stmt.setObject(param, value); 194 } 195 } 196 197 @Override 198 public String toString() { 199 return "Binders.timeBinder"; 200 } 201 } 202 203 /** 204 * The implementation for {@link Binders#integerBinder()} 205 * @author JB Nizet 206 */ 207 private static final class IntegerBinder implements Binder { 208 @Override 209 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 210 if (value instanceof BigInteger) { 211 stmt.setObject(param, value, Types.BIGINT); 212 } 213 else if (value instanceof Enum<?>) { 214 stmt.setInt(param, ((Enum<?>) value).ordinal()); 215 } 216 else if (value instanceof String) { 217 stmt.setObject(param, new BigInteger((String) value), Types.BIGINT); 218 } 219 else { 220 stmt.setObject(param, value); 221 } 222 } 223 224 @Override 225 public String toString() { 226 return "Binders.integerBinder"; 227 } 228 } 229 230 /** 231 * The implementation for {@link Binders#decimalBinder()} 232 * @author JB Nizet 233 */ 234 private static final class DecimalBinder implements Binder { 235 @Override 236 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 237 if (value instanceof String) { 238 stmt.setBigDecimal(param, new BigDecimal((String) value)); 239 } 240 else { 241 stmt.setObject(param, value); 242 } 243 } 244 245 @Override 246 public String toString() { 247 return "Binders.decimalBinder"; 248 } 249 } 250 251 /** 252 * The implementation for {@link Binders#timestampBinder()} 253 * @author JB Nizet 254 */ 255 private static final class TimestampBinder implements Binder { 256 // the number of chars in yyyy-mm-dd hh:mm:ss 257 private static final int MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP = 19; 258 259 @Override 260 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 261 if (value instanceof Timestamp) { 262 stmt.setTimestamp(param, (Timestamp) value); 263 } 264 else if (value instanceof java.util.Date) { 265 stmt.setTimestamp(param, new Timestamp(((java.util.Date) value).getTime())); 266 } 267 else if (value instanceof java.util.Calendar) { 268 stmt.setTimestamp(param, new Timestamp(((java.util.Calendar) value).getTimeInMillis())); 269 } 270 else if (value instanceof String) { 271 String valueAsString = (String) value; 272 if (valueAsString.length() >= MIN_NUMBER_OF_CHARS_FOR_TIMESTAMP) { 273 stmt.setTimestamp(param, Timestamp.valueOf(valueAsString)); 274 } 275 else { 276 Date valueAsDate = Date.valueOf(valueAsString); 277 stmt.setTimestamp(param, new Timestamp(valueAsDate.getTime())); 278 } 279 } 280 else { 281 stmt.setObject(param, value); 282 } 283 } 284 285 @Override 286 public String toString() { 287 return "Binders.timestampBinder"; 288 } 289 } 290 291 /** 292 * The implementation for {@link Binders#dateBinder()} 293 * @author JB Nizet 294 */ 295 private static final class DateBinder implements Binder { 296 @Override 297 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 298 if (value instanceof Date) { 299 stmt.setDate(param, (Date) value); 300 } 301 else if (value instanceof java.util.Date) { 302 stmt.setDate(param, new Date(((java.util.Date) value).getTime())); 303 } 304 else if (value instanceof java.util.Calendar) { 305 stmt.setDate(param, new Date(((java.util.Calendar) value).getTimeInMillis())); 306 } 307 else if (value instanceof String) { 308 stmt.setDate(param, Date.valueOf((String) value)); 309 } 310 else { 311 stmt.setObject(param, value); 312 } 313 } 314 315 @Override 316 public String toString() { 317 return "Binders.dateBinder"; 318 } 319 } 320 321 /** 322 * The implementation for {@link Binders#defaultBinder()} 323 * @author JB Nizet 324 */ 325 private static final class DefaultBinder implements Binder { 326 @Override 327 public void bind(java.sql.PreparedStatement stmt, int param, Object value) throws java.sql.SQLException { 328 stmt.setObject(param, value); 329 } 330 331 @Override 332 public String toString() { 333 return "Binders.defaultBinder"; 334 } 335 } 336 }