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() 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 }