1 /* 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.sql.rowset.serial; 27 28 import java.sql.*; 29 import javax.sql.*; 30 import java.io.*; 31 import java.math.*; 32 import java.util.Arrays; 33 import java.util.Map; 34 import java.util.Vector; 35 36 import javax.sql.rowset.*; 37 38 /** 39 * A serialized mapping in the Java programming language of an SQL 40 * structured type. Each attribute that is not already serialized 41 * is mapped to a serialized form, and if an attribute is itself 42 * a structured type, each of its attributes that is not already 43 * serialized is mapped to a serialized form. 44 * <P> 45 * In addition, the structured type is custom mapped to a class in the 46 * Java programming language if there is such a mapping, as are 47 * its attributes, if appropriate. 48 * <P> 49 * The <code>SerialStruct</code> class provides a constructor for creating 50 * an instance from a <code>Struct</code> object, a method for retrieving 51 * the SQL type name of the SQL structured type in the database, and methods 52 * for retrieving its attribute values. 53 * 54 * <h3> Thread safety </h3> 55 * 56 * A SerialStruct is not safe for use by multiple concurrent threads. If a 57 * SerialStruct is to be used by more than one thread then access to the 58 * SerialStruct should be controlled by appropriate synchronization. 59 * 60 * @since 1.5 61 */ 62 public class SerialStruct implements Struct, Serializable, Cloneable { 63 64 65 /** 66 * The SQL type name for the structured type that this 67 * <code>SerialStruct</code> object represents. This is the name 68 * used in the SQL definition of the SQL structured type. 69 * 70 * @serial 71 */ 72 private String SQLTypeName; 73 74 /** 75 * An array of <code>Object</code> instances in which each 76 * element is an attribute of the SQL structured type that this 77 * <code>SerialStruct</code> object represents. The attributes are 78 * ordered according to their order in the definition of the 79 * SQL structured type. 80 * 81 * @serial 82 */ 83 private Object attribs[]; 84 85 /** 86 * Constructs a <code>SerialStruct</code> object from the given 87 * <code>Struct</code> object, using the given <code>java.util.Map</code> 88 * object for custom mapping the SQL structured type or any of its 89 * attributes that are SQL structured types. 90 * 91 * @param in an instance of {@code Struct} 92 * @param map a <code>java.util.Map</code> object in which 93 * each entry consists of 1) a <code>String</code> object 94 * giving the fully qualified name of a UDT and 2) the 95 * <code>Class</code> object for the <code>SQLData</code> implementation 96 * that defines how the UDT is to be mapped 97 * @throws SerialException if an error occurs 98 * @see java.sql.Struct 99 */ 100 public SerialStruct(Struct in, Map<String,Class<?>> map) 101 throws SerialException 102 { 103 104 try { 105 106 // get the type name 107 SQLTypeName = in.getSQLTypeName(); 108 System.out.println("SQLTypeName: " + SQLTypeName); 109 110 // get the attributes of the struct 111 attribs = in.getAttributes(map); 112 113 /* 114 * the array may contain further Structs 115 * and/or classes that have been mapped, 116 * other types that we have to serialize 117 */ 118 mapToSerial(map); 119 120 } catch (SQLException e) { 121 throw new SerialException(e.getMessage()); 122 } 123 } 124 125 /** 126 * Constructs a <code>SerialStruct</code> object from the 127 * given <code>SQLData</code> object, using the given type 128 * map to custom map it to a class in the Java programming 129 * language. The type map gives the SQL type and the class 130 * to which it is mapped. The <code>SQLData</code> object 131 * defines the class to which the SQL type will be mapped. 132 * 133 * @param in an instance of the <code>SQLData</code> class 134 * that defines the mapping of the SQL structured 135 * type to one or more objects in the Java programming language 136 * @param map a <code>java.util.Map</code> object in which 137 * each entry consists of 1) a <code>String</code> object 138 * giving the fully qualified name of a UDT and 2) the 139 * <code>Class</code> object for the <code>SQLData</code> implementation 140 * that defines how the UDT is to be mapped 141 * @throws SerialException if an error occurs 142 */ 143 public SerialStruct(SQLData in, Map<String,Class<?>> map) 144 throws SerialException 145 { 146 147 try { 148 149 //set the type name 150 SQLTypeName = in.getSQLTypeName(); 151 152 Vector<Object> tmp = new Vector<>(); 153 in.writeSQL(new SQLOutputImpl(tmp, map)); 154 attribs = tmp.toArray(); 155 156 } catch (SQLException e) { 157 throw new SerialException(e.getMessage()); 158 } 159 } 160 161 162 /** 163 * Retrieves the SQL type name for this <code>SerialStruct</code> 164 * object. This is the name used in the SQL definition of the 165 * structured type 166 * 167 * @return a <code>String</code> object representing the SQL 168 * type name for the SQL structured type that this 169 * <code>SerialStruct</code> object represents 170 * @throws SerialException if an error occurs 171 */ 172 public String getSQLTypeName() throws SerialException { 173 return SQLTypeName; 174 } 175 176 /** 177 * Retrieves an array of <code>Object</code> values containing the 178 * attributes of the SQL structured type that this 179 * <code>SerialStruct</code> object represents. 180 * 181 * @return an array of <code>Object</code> values, with each 182 * element being an attribute of the SQL structured type 183 * that this <code>SerialStruct</code> object represents 184 * @throws SerialException if an error occurs 185 */ 186 public Object[] getAttributes() throws SerialException { 187 Object[] val = this.attribs; 188 return (val == null) ? null : Arrays.copyOf(val, val.length); 189 } 190 191 /** 192 * Retrieves the attributes for the SQL structured type that 193 * this <code>SerialStruct</code> represents as an array of 194 * <code>Object</code> values, using the given type map for 195 * custom mapping if appropriate. 196 * 197 * @param map a <code>java.util.Map</code> object in which 198 * each entry consists of 1) a <code>String</code> object 199 * giving the fully qualified name of a UDT and 2) the 200 * <code>Class</code> object for the <code>SQLData</code> implementation 201 * that defines how the UDT is to be mapped 202 * @return an array of <code>Object</code> values, with each 203 * element being an attribute of the SQL structured 204 * type that this <code>SerialStruct</code> object 205 * represents 206 * @throws SerialException if an error occurs 207 */ 208 public Object[] getAttributes(Map<String,Class<?>> map) 209 throws SerialException 210 { 211 Object[] val = this.attribs; 212 return (val == null) ? null : Arrays.copyOf(val, val.length); 213 } 214 215 216 /** 217 * Maps attributes of an SQL structured type that are not 218 * serialized to a serialized form, using the given type map 219 * for custom mapping when appropriate. The following types 220 * in the Java programming language are mapped to their 221 * serialized forms: <code>Struct</code>, <code>SQLData</code>, 222 * <code>Ref</code>, <code>Blob</code>, <code>Clob</code>, and 223 * <code>Array</code>. 224 * <P> 225 * This method is called internally and is not used by an 226 * application programmer. 227 * 228 * @param map a <code>java.util.Map</code> object in which 229 * each entry consists of 1) a <code>String</code> object 230 * giving the fully qualified name of a UDT and 2) the 231 * <code>Class</code> object for the <code>SQLData</code> implementation 232 * that defines how the UDT is to be mapped 233 * @throws SerialException if an error occurs 234 */ 235 private void mapToSerial(Map<String,Class<?>> map) throws SerialException { 236 237 try { 238 239 for (int i = 0; i < attribs.length; i++) { 240 if (attribs[i] instanceof Struct) { 241 attribs[i] = new SerialStruct((Struct)attribs[i], map); 242 } else if (attribs[i] instanceof SQLData) { 243 attribs[i] = new SerialStruct((SQLData)attribs[i], map); 244 } else if (attribs[i] instanceof Blob) { 245 attribs[i] = new SerialBlob((Blob)attribs[i]); 246 } else if (attribs[i] instanceof Clob) { 247 attribs[i] = new SerialClob((Clob)attribs[i]); 248 } else if (attribs[i] instanceof Ref) { 249 attribs[i] = new SerialRef((Ref)attribs[i]); 250 } else if (attribs[i] instanceof java.sql.Array) { 251 attribs[i] = new SerialArray((java.sql.Array)attribs[i], map); 252 } 253 } 254 255 } catch (SQLException e) { 256 throw new SerialException(e.getMessage()); 257 } 258 return; 259 } 260 261 /** 262 * Compares this SerialStruct to the specified object. The result is 263 * {@code true} if and only if the argument is not {@code null} and is a 264 * {@code SerialStruct} object whose attributes are identical to this 265 * object's attributes 266 * 267 * @param obj The object to compare this {@code SerialStruct} against 268 * 269 * @return {@code true} if the given object represents a {@code SerialStruct} 270 * equivalent to this SerialStruct, {@code false} otherwise 271 * 272 */ 273 public boolean equals(Object obj) { 274 if (this == obj) { 275 return true; 276 } 277 if (obj instanceof SerialStruct) { 278 SerialStruct ss = (SerialStruct)obj; 279 return SQLTypeName.equals(ss.SQLTypeName) && 280 Arrays.equals(attribs, ss.attribs); 281 } 282 return false; 283 } 284 285 /** 286 * Returns a hash code for this {@code SerialStruct}. The hash code for a 287 * {@code SerialStruct} object is computed using the hash codes 288 * of the attributes of the {@code SerialStruct} object and its 289 * {@code SQLTypeName} 290 * 291 * @return a hash code value for this object. 292 */ 293 public int hashCode() { 294 return ((31 + Arrays.hashCode(attribs)) * 31) * 31 295 + SQLTypeName.hashCode(); 296 } 297 298 /** 299 * Returns a clone of this {@code SerialStruct}. The copy will contain a 300 * reference to a clone of the underlying attribs array, not a reference 301 * to the original underlying attribs array of this {@code SerialStruct} object. 302 * 303 * @return a clone of this SerialStruct 304 */ 305 public Object clone() { 306 try { 307 SerialStruct ss = (SerialStruct) super.clone(); 308 ss.attribs = Arrays.copyOf(attribs, attribs.length); 309 return ss; 310 } catch (CloneNotSupportedException ex) { 311 // this shouldn't happen, since we are Cloneable 312 throw new InternalError(); 313 } 314 315 } 316 317 /** 318 * readObject is called to restore the state of the {@code SerialStruct} from 319 * a stream. 320 */ 321 private void readObject(ObjectInputStream s) 322 throws IOException, ClassNotFoundException { 323 324 ObjectInputStream.GetField fields = s.readFields(); 325 Object[] tmp = (Object[])fields.get("attribs", null); 326 attribs = tmp == null ? null : tmp.clone(); 327 SQLTypeName = (String)fields.get("SQLTypeName", null); 328 } 329 330 /** 331 * writeObject is called to save the state of the {@code SerialStruct} 332 * to a stream. 333 */ 334 private void writeObject(ObjectOutputStream s) 335 throws IOException, ClassNotFoundException { 336 337 ObjectOutputStream.PutField fields = s.putFields(); 338 fields.put("attribs", attribs); 339 fields.put("SQLTypeName", SQLTypeName); 340 s.writeFields(); 341 } 342 343 /** 344 * The identifier that assists in the serialization of this 345 * <code>SerialStruct</code> object. 346 */ 347 static final long serialVersionUID = -8322445504027483372L; 348 }