001    package biz.hammurapi.sql;
002    
003    import java.io.Serializable;
004    import java.lang.reflect.Method;
005    import java.sql.PreparedStatement;
006    import java.sql.SQLException;
007    
008    import biz.hammurapi.sql.columns.ObjectColumn;
009    
010    /**
011     * Wrapper for different types.
012     * @author Pavel
013     */
014    public class Variant implements Parameterizer, Serializable {
015            
016            private static final int TYPE_BOOLEAN = 0;
017            private static final int TYPE_BYTE = 1;
018            private static final int TYPE_CHAR = 2;
019            private static final int TYPE_DOUBLE = 3;
020            private static final int TYPE_FLOAT = 4;
021            private static final int TYPE_INT = 5;
022            private static final int TYPE_LONG = 6;
023            private static final int TYPE_STRING = 7;
024            private static final int TYPE_OBJECT = 8;
025            private static final int TYPE_TYPED_OBJECT = 9;
026            private static final int TYPE_SHORT = 10;
027    
028            private int type;
029            
030            private boolean booleanValue;
031            private byte byteValue;
032            private char charValue;
033            private double doubleValue;
034            private float floatValue;
035            private int intValue;
036            private long longValue;
037            private String stringValue;
038            private Object objectValue;
039            private int sqlType;
040            private short shortValue;
041            
042            public Variant(boolean value) {
043                    type = TYPE_BOOLEAN;
044                    this.booleanValue = value;
045            }
046    
047            public Variant(byte value) {
048                    type = TYPE_BYTE;
049                    this.byteValue = value;
050            }
051    
052            public Variant(char value) {
053                    type = TYPE_CHAR;
054                    this.charValue = value;
055            }
056    
057            public Variant(double value) {
058                    type = TYPE_DOUBLE;
059                    this.doubleValue = value;
060            }
061    
062            public Variant(float value) {
063                    type = TYPE_FLOAT;
064                    this.floatValue = value;
065            }
066    
067            public Variant(int value) {
068                    type = TYPE_INT;
069                    this.intValue = value;
070            }
071    
072            public Variant(long value) {
073                    type = TYPE_LONG;
074                    this.longValue = value;
075            }
076    
077            public Variant(String value) {
078                    type = TYPE_STRING;
079                    this.stringValue = value;
080            }
081    
082            public Variant(Object value) {
083                    type = TYPE_OBJECT;
084                    this.objectValue = value;
085            }
086    
087            public Variant(Object value, int sqlType) {
088                    type = TYPE_TYPED_OBJECT;
089                    this.objectValue = value;
090                    this.sqlType = sqlType;
091            }
092            
093            public Variant(short value) {
094                    type = TYPE_SHORT;
095                    this.shortValue = value;
096            }
097            
098            public int parameterize(PreparedStatement ps, int idx) throws SQLException {
099                    switch (type) {
100                            case TYPE_BOOLEAN:
101                                    ps.setBoolean(idx++, booleanValue);
102                                    break;                          
103                            case TYPE_BYTE:
104                                    ps.setByte(idx++, byteValue);
105                                    break;                          
106                            case TYPE_CHAR:
107                                    ps.setString(idx++, ""+charValue);
108                                    break;                          
109                            case TYPE_DOUBLE:
110                                    ps.setDouble(idx++, doubleValue);
111                                    break;                          
112                            case TYPE_FLOAT:
113                                    ps.setFloat(idx++, floatValue);
114                                    break;                          
115                            case TYPE_INT:
116                                    ps.setInt(idx++, intValue);
117                                    break;                          
118                            case TYPE_LONG:
119                                    ps.setLong(idx++, longValue);
120                                    break;                          
121                            case TYPE_STRING:
122                                    ps.setString(idx++, stringValue);
123                                    break;                          
124                            case TYPE_OBJECT:
125                                    Method setter = ObjectColumn.findSetter(objectValue.getClass());
126                                    if ("setObject".equals(setter.getName())) {
127                                            ps.setObject(idx++, objectValue);
128                                    } else {
129                                            try {
130                                                    setter.invoke(ps, new Object[] {new Integer(idx++), objectValue});
131                                            } catch (Exception e) {
132                                                    Throwable cause = e;
133                                                    while (cause.getCause()!=null && cause.getCause()!=cause) {
134                                                            cause = cause.getCause();
135                                                    }
136                                                    if (cause instanceof SQLException) {
137                                                            throw (SQLException) cause;
138                                                    } else {
139                                                            throw new SQLRuntimeException(e);
140                                                    }
141                                            }
142                                    }
143                                    break;                          
144                            case TYPE_TYPED_OBJECT:
145                                    ps.setObject(idx++, objectValue, sqlType);
146                                    break;                          
147                            case TYPE_SHORT:
148                                    ps.setShort(idx++, shortValue);
149                                    break;                          
150                            default:
151                                    throw new SQLException("Unrecognized value type: "+type);
152                    } 
153                    return idx;
154            }
155    
156            public int hashCode() {
157                    final int prime = 31;
158                    int result = 1;
159                    result = prime * result + (booleanValue ? 1231 : 1237);
160                    result = prime * result + charValue;
161                    long temp;
162                    temp = Double.doubleToLongBits(doubleValue);
163                    result = prime * result + (int) (temp ^ (temp >>> 32));
164                    result = prime * result + Float.floatToIntBits(floatValue);
165                    result = prime * result + intValue;
166                    result = prime * result + (int) (longValue ^ (longValue >>> 32));
167                    result = prime * result
168                                    + ((objectValue == null) ? 0 : objectValue.hashCode());
169                    result = prime * result + shortValue;
170                    result = prime * result + sqlType;
171                    result = prime * result
172                                    + ((stringValue == null) ? 0 : stringValue.hashCode());
173                    result = prime * result + type;
174                    return result;
175            }
176    
177            public boolean equals(Object obj) {
178                    if (this == obj)
179                            return true;
180                    if (obj == null)
181                            return false;
182                    if (getClass() != obj.getClass())
183                            return false;
184                    final Variant other = (Variant) obj;
185                    if (booleanValue != other.booleanValue)
186                            return false;
187                    if (byteValue != other.byteValue)
188                            return false;
189                    if (charValue != other.charValue)
190                            return false;
191                    if (Double.doubleToLongBits(doubleValue) != Double
192                                    .doubleToLongBits(other.doubleValue))
193                            return false;
194                    if (Float.floatToIntBits(floatValue) != Float
195                                    .floatToIntBits(other.floatValue))
196                            return false;
197                    if (intValue != other.intValue)
198                            return false;
199                    if (longValue != other.longValue)
200                            return false;
201                    if (objectValue == null) {
202                            if (other.objectValue != null)
203                                    return false;
204                    } else if (!objectValue.equals(other.objectValue))
205                            return false;
206                    if (shortValue != other.shortValue)
207                            return false;
208                    if (sqlType != other.sqlType)
209                            return false;
210                    if (stringValue == null) {
211                            if (other.stringValue != null)
212                                    return false;
213                    } else if (!stringValue.equals(other.stringValue))
214                            return false;
215                    if (type != other.type)
216                            return false;
217                    return true;
218            }
219    
220    }